8 ms·
Wait, you had an object that was unsafe to copy, but you told the computer it was safe by not deleting the copy constructor? I guess it should have done what yo
by bregma 5y ago
Wait, you had an object that was unsafe to copy, but you told the computer it was safe by not deleting the copy constructor? I guess it should have done what you wanted, not what you told it.
- secondcoming 5y agoNo, everyone gets LHS auto wrong at the start. They don't realise it makes a copy. I have to point it out every other code review.
- jcelerier 5y agoThe rule is simple: auto behaves like a template parameter
- Koshkin 5y agoAh, templates... Universal references... Good stuff.
- Kranar 5y agoYep, except now we're supposed to call them forwarding references because the motivation Scott Meyers had for naming them universal references turned out to be incorrect in subtle ways. Even the notable experts get things wrong when it comes to how complex and bloated C++ is.
- Kranar 5y agoThere is nothing simple about that (not to mention it's not actually true either).
- jcelerier 5y agoYes it is ? Quoting the standard: > If the placeholder-type-specifier is of the form type-constraint auto, the deduced type T' replacing T is determined using the rules for template argument deduction. https://eel.is/c++draft/dcl.spec.auto https://eel.is/c++draft/dcl.spec.auto Now if you program in C++ regularly and don't know that in template<typename T> void f(T t) { } f(something); does a copy of something, I don't know what to say - I have never met any professional c++ programmer not knowing the language works that way
- Kranar 5y agoYou need to continue reading that paragraph to the very end and note the exception for when an initializer list is used. The following are not equivalent nor do they apply the same rules: template<typename T> void f(T) {} f({1, 2, 3}); auto x = {1, 2, 3}; >Now if you program in C++ regularly and don't know that in... I program in C++ daily and no, I didn't know that a copy is made. What I do know, as an actual professional C++ programmer, is that whether a copy is performed is incredibly complex and depends on numerous factors such as whether a move constructor exists and "something" is an lvalue but not an rvalue reference, or if "something" is an rvalue (which is not the same as an rvalue reference) and T defines a move constructor. And finally if something is the same type as T and T has a copy constructor, then the final question is whether copy elision will be performed, which the standard specifies is a valid optimization even if said optimization would change the observable behavior of the program. That's what I... as a professional C++ programmer know but I fully admit that C++ is such a complex beast of a language that I am almost definitely missing a few corner cases.
- jcelerier 5y ago> You need to continue reading that paragraph to the very end and note the exception for when an initializer list is used. Exceptions don't mean that the general rule does not apply ? I don't know how it is possible to be more explicit that "the deduced type T' replacing T is determined using the rules for template argument deduction.". That'd be like saying that "priority to the right" when driving isn't a rule because there is sometimes a "stop". > I program in C++ daily and no, I didn't know that a copy is made. you're kidding > whether a copy is performed is incredibly complex and depends on numerous factors such as whether a move constructor exists and "something" is an lvalue but not an rvalue reference, or if "something" is an rvalue (which is not the same as an rvalue reference) and T defines a move constructor. but `something` cannot be a rvalue in f(something); maybe in f(something()); or f(some + thing); but just a variable named "something", as is, passed to a template argument or auto will necessarily lead to the creation of a new value of the same type. Whether it is copied, moved, materializes three different types because people forgot to mark their constructors explicit or whatever else frankly does not matter much in my experience (after all people survived for 30 years without move semantics) - what matters is whether a new value is created (which I personally and improperly call a "copy" no matter what - I should have been more precise but it's really the most useful distinction to make in practice imho as it means that some function will be called) or just a reference to existing value which is always a no-op no matter what. > And finally if something is the same type as T and T has a copy constructor, then the final question is whether copy elision will be performed, I've been at it for 15 years now and I don't remember one time in non-toy-example-code where copy elision taking place or not did matter. Thinking about is is a self-inflicted problem ; expect that a copy happens, if it's slow, profile and if it's not, be happy.
- suprfsat 5y agoSimply by using C++, you tell the computer all sorts of things, such as "I know the entire language by heart", and "I have a death wish".
- owl57 5y agoWhile C++ is a dangerous tool indeed, ignoring the rule of 5 is analogous to ignoring the safety guidelines, not simply using the tool.
- MaxBarraclough 5y agoI'm reminded of a quote about C, sadly I forget where it's from: > It is fundamental tenet of C's philosophy that the programmer is always right, even when they are wrong.
- overgard 5y agoHonestly I think that's what makes it (and C++) a great tool, despite the frustrations. I'd rather have a footgun than a nerf gun.
- MaxBarraclough 5y ago> I'd rather have a footgun than a nerf gun. That's not really the choice we're faced with though. Ada and Rust are both far safer than C, and they're also plenty powerful.
- contravariant 5y agoYeah I learned that the hard way when I found out that std::vector apparently feels free to move your objects around in memory for you, no matter if you point to them from somewhere else. I mean in hindsight it's obvious, but still not exactly what I wanted to happen. For reference, what I did does actually work, temporarily.
- tines 5y ago> Yeah I learned that the hard way when I found out that std::vector apparently feels free to move your objects around in memory for you In standard terminology, this is described as "invalidating iterators". There are a bunch of member functions in std::vector that either do or don't invalidate iterators, e.g. push_back(...) does but size() doesn't. And as the name implies, if you call a function that invalidates iterators, all your existing iterators/pointers/references become invalid.
- Kranar 5y agoIterator invalidation is different from this. Iterator invalidation, as the name suggests, only applies to iterators. The problem OP was having had to do with dangling references. Some containers guarantee references won't dangle on mutation such as unordered_map. An unordered_map may invalidate iterators if objects are added or removed, but will never result in dangling references (unless the object is removed). That is, it is safe to have a pointer to an object owned by an unordered_map and continue using that pointer even after an iterator to that same object is invalidated.
- tines 5y agoAh, interesting. Even within that dichotomy, I'd think that if references aren't invalidated on mutation, then dereferencing iterators would be valid, but incrementing them would not be.
- einpoklum 5y agoIterators are historically a generalization of pointers. A pointer is a kind of iterator. I mean, literally. The iterator of an std::vector<T> (not a bool vector) is a T*.
- Dylan16807 5y ago> told the computer it was safe > by not deleting I think there's a problem here.
- junon 5y agoProbably one of the only common language-lawyer pieces of criticism of C++ I fully agree with. I'm a pretty firm believer that a language should be as constrained as possible with the ability to make it explicitly less-constrained. C++ fails at this pretty spectacularly.
- initplus 5y agoRule of three is such a common C++ concept though, I would be surprised if anyone with more than a few weeks experience with the language is still running into such issues.
- overgard 5y agoI've been coding C++ off and on since 1998. But not all the code I use is written by me... not even most of it. I'd love it if everyone followed best practices... but they don't.
- rualca 5y ago> I think there's a problem here. There is a problem indeed, which is OP's failure to implement exception-safe code. If someone opts to use exceptions, they have the responsibility of writing their code in a way that complies with scenarios involving throwing exceptions. Failing to support a scenario by not following the most basic principles is something that's on the person writing the code, not the language. It would make as much sense to blame java for the problems you create by not initializing objects in some code paths, because your code started to throw null pointer exceptions.
- Dylan16807 5y agoAre you talking about the same thing as everyone else? auto fooRef = myWidget.getRef(); vs. auto& fooRef = myWidget.getRef();? That's not a problem caused by exceptions. If you're talking about the article, the standards committee seems to think it's a confusing interpretation that never should have existed, and it's pretty ridiculous to say it's "basic principles".
- overgard 5y agoWell, the scene graph code wasn't code I wrote, and this was back in 2014. But sure, obviously it was an error on my part... we are talking about footguns afterall, I'm the one that pulled the trigger.