5 ms·
We have just started using some C++11 features, and with new features come new traps and potential complexities, as you'd expect with C++. A few examples: 1.
by obiterdictum 15y ago
We have just started using some C++11 features, and with new features come new traps and potential complexities, as you'd expect with C++.
A few examples:
1. Implicit lambdas ("[=]") capture "this" pointer for data members, if you capture a shared pointer and let the lambda object leave the scope, the shared pointer won't be copied (http://stackoverflow.com/q/7764564/23643 http://stackoverflow.com/q/7764564/23643), which may create unpleasant results, like code blowing up in your face.
2. Overuse of "auto" (not exclusive to C++) may make the code harder to read, especially if storing a result returned from a function. You can't tell if the return value is a smart pointer or a raw pointer, value or a reference, so you can't figure ownership semantics just by looking at the local code.
3. Move constructors/assignment operators are a bit of a black magic, especially with regard to suppressing default implementation (http://mmocny.wordpress.com/2010/12/09/implicit-move-wont-go http://mmocny.wordpress.com/2010/12/09/implicit-move-wont-go) and exception safety (http://cpp-next.com/archive/2009/10/exceptionally-moving http://cpp-next.com/archive/2009/10/exceptionally-moving). I would refrain from using it, until I fully understand it.
With that said, most of C++11 is a welcome change and makes C++ more pleasant to write, but, as always, you have to have your guard up and use new features judiciously.
- alecthomas 15y agoGood points. Re. 2, we decided to only use auto for iterators, which eradicated a large amount of boilerplate without being too confusing.
- iam 15y agoWow that's interesting. Never realized lambdas capture "this" and not the actual data members itself! That also means you can get in big trouble if the object that got captured was deleted, ouch.
- ajross 15y agoThis is why Lisp never had manual allocation. It's a booby trap for a new generation, kind of like the collision between heap allocation and exceptions was in our youth.
- ajross 15y agoC++ always seems to lead to traps. In point #2, you're obviously right about the micro-coding/readability point. But the premise is kind of scary: you're dealing with a code base where the ownership semantics of an object are captured only by a function return type? Yikes. That's a framework issue: if everyone working on the source isn't 100% sure what that return means, you're guaranteed to get bugs with or without auto. Non-trivial ownership/allocation/copy semantics (i.e. anything other than "on the stack" or "operator new") are deep C++ voodoo, not something you worry about in passing as a readability thing.
- jemfinch 15y agoAt least you can express ownership semantics in C++ code, using constructs like `unique_ptr`, `scoped_ptr`, and `shared_ptr`. In a garbage collected language, nothing expresses ownership, and so while you not be at risk of memory leaks, you're still vulnerable to all the other bugs that come with aliasing mutable objects. The "framework issue" you describe is solved precisely by specifying ownership semantics in terms of smart pointer return values. The way everyone becomes "100% sure what that return means" is by whether it returns a `unique_ptr` or a `shared_ptr`. The OP is simply complaining that `auto` takes away that local information on ownership. `operator new()` is only trivial by virtue of not specifying anything at all about ownership. `scoped_ptr` and `shared_ptr` and `unique_ptr` are each specifying different, more restricted, but still trivial ownership semantics. They aren't "deep C++ voodoo" in the least. Your post smacks of someone who doesn't actually write C++ for a living.
- oconnore 15y ago> In a garbage collected language, nothing expresses ownership, and so while you not be at risk of memory leaks, you're still vulnerable to all the other bugs that come with aliasing mutable objects. You are conflating required language features with proper API design and documentation. I don't need '(unique|scoped|shared)_ptr' to refrain from aliasing mutable types, or to document my code properly on the rare occasion when I am required to.
- cpeterso 15y ago
- dilap 15y agoComing from a dynamically-typed language perspective, (2) seems like incredibly not a big deal. If you're unclear on the return type, just look at the declaration of the function that's being called. Compare this to, e.g., Python, where you have to look at the actual definition of the function being called (and maybe eve n the definition of functions it calls, and so on), which is way worse.
- rayiner 15y agoDynamically typed languages respond to the problem in (2) by keeping typing simple. C++'s proliferation of multiple ways to do the same thing (regular pointer, smart pointer, reference, etc) and multiplicity of ownership rule (no GC) cuts across that.
- dilap 15y agoIt's certainly true that dynamic, high-level languages save you from having to worry about ownership-semantics, but you still care a lot about the return-type (e.g., am I getting back an int, a str, a set, a dict, a simple list, a generator, &c &c &c)! You care about this; either it must be obvious (e.g., fairly obvious with a function like len()), or you have to look it up in the documentation or comments of the function. If it's not documented, you have to try to figure it out from the function body, which is often non-trivial. This is why you'll typically see what amounts informal type annotations in the comments of functions of mature code. Despite all this, many people feel that the flexibility of not having to specify types is a net-win. C++ "auto" adds some of the convenience, but at a much lower cost in readibility, since when you see something like auto x = foo.gimmeBar(); you can find out the type of x immediately just by looking at the definition of gimmeBar() (with IDE support, this could even be zero-effort (i.e., it could show a little grey popup bubble with the deduced type); even with something old-fashioned like emacs+ctags, it's just a hop-skip-and-a-jump away). * By the way, regarding ownership-semantics, it's true they could be a massive PITA pre-C++11, and (sort of analogously to the what-are-the-types-in-a-dynamic-language situation) you'd often have to fall back to relying on comments to know what was going on. If they're weren't comments and you were getting back a raw pointer, well...that could be rough. This is a problem that can be fixed with library support (for smart pointers) and disciplined coding -- i.e., using the smart pointers. For a good example of this working really well in practice, see Objective-C. C++11 helps because it gives us built-in library support, and will hopefully provide the community motivation for the convention/discipline of actually using the libs. (This pointer-ownership stuff is pretty much orthogonal to auto, though, IMO.)
- apaprocki 15y ago2. I'm sure IDEs/editors will start to implement features to grok object output and/or do static analysis to show you what type auto implies. It isn't necessarily easy but it seems like the feature everyone would want. You could even produce a "de-auto" button that would toggle between auto and the substituted real type for readability. 3. Move operations are completely welcome as far as I'm concerned. I recently hit some performance problems which beg for move or emplace semantics. Most people don't realize the amount of copies they are making when using STL containers. These semantics will allow code to ensure only one instance of a value type is ever created when, say, inserting into a map. I feel like some people resort to going back to hand-rolled data structures or raw pointers when performance is critical because the current containers are missing this.
- CJefferson 15y agoIn templates, it is almost impossible to remove the 'auto'. Even something simple like: template<typename T> void f(T t1, T t2) { auto sum = t1 + t2; } There is nothing to replace auto with. Similar things apply to most templated functions. Of course outside of templates things get much easier, but I wouldn't expect to see quite so many autos.
- dilap 15y agoTrue, but at least screw-ups will be noticed at compile time. And how would you even write this snippet, pre auto?! (I think you'd either just assume t1 + t2 was T, or you'd have to go thru less-general, even-less-clear, gymnastics (like having some structure defined like get_sum_type<T,T>::thetype sum = t1 + t2).)
- koenigdavidmj 15y ago>And how would you even write this snippet, pre auto?! typeof(t1 + t2) sum = t1 + t2;
- koenigdavidmj 15y ago