But wait a second, what if the user uses boost::swap instead of std::swap? Or better yet, a custom implementation of swap?
I suppose that's their own fault for not using the build in method Foo::swap.
But wait a second, what if the user uses boost::swap instead of std::swap? Or better yet, a custom implementation of swap?
I suppose that's their own fault for not using the build in method Foo::swap.
boost::swap will call std::swap() if ADL doesn't look-up swap() in the namespace of the arguments.
Emphasis mine.The user should call unqualified swap, so that ADL has a chance to kick in. So swap should be a free standing function in the same namespace as the class it swaps.
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
That's odd, because I've been encouraged to use exceptions if it makes sense. There's an entire section on when and when not to use exceptions here: http://www.parashift.com/c++-faq-lite/exceptions.htmlThis is off topic, but: in 99% of the C++ projects I've worked on, exceptions have been banned by the programming guidelines/standards
Writing exception-safe code is very important if you're writing the standard library that will be used by everyone, but in my own experience, it's not something that is required in order to work on most C++ projects.
I really think it only makes sense to throw an exception when you've got a ctor error and you want to catch it somewhere. Otherwise I only really use them to crash the program in such a way that will take me directly to the error (just throwing a string literal). Apart from that, I find them to be more of a PITA and a bogeyman than anything else.
I was reading up on the rule of 3, and found a more elegant way of overriding the assignment operator. The way I initially learned to do it was something like this:HOWEVER, this is not exception safe (for instance, if you are allocating new objects during the copying of resources, and any one of them throws an exception, you'll be looking at a memory leak) and it performs needless checks for self assignment.class Foo { public: Foo& operator=( const Foo& cp ) { if( this == &cp ) return *this; // copy resources here return *this; } };
Oh? Here you go...
class Foo {
public:
Foo& operator=(const Foo& cp) {
if(this == &cp) return *this;
//use RAII here
return *this;
}
};
Problem solved!
I get the idea of copy and swap, but you're really just offloading the work to the copy ctor, aren't you? You could just as easily write the code into the assignment operator and then write the copy ctor to just call the assignment operator. If you're copying resources then you have to write the explicit copy behaviors somewhere.
I suppose it doesn't matter too much which approach a the implementer of swap is using. On the user side, that's where you want to make sure ADL is supported, especially for template code that isn't aware of the types it's instantiated with. So given such support, I think using ADL is a bit more elegant than adding things to namespace std, especially if the implementation of swap needs to access the private interface of the class -- that is, it's a friend function.Emphasis mine.The user should call unqualified swap, so that ADL has a chance to kick in. So swap should be a free standing function in the same namespace as the class it swaps.
Are you sure about that? The C++ standard explicitly allows for template specializations (not overloads) to be added to the std namespace.
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
I'm not actually sure what is considered best practice anymore.
Emphasis mine.The user should call unqualified swap, so that ADL has a chance to kick in. So swap should be a free standing function in the same namespace as the class it swaps.
Are you sure about that? The C++ standard explicitly allows for template specializations (not overloads) to be added to the std namespace.
You're not writing classes in the std namespace, so you don't put your custom swap functions in the std namespace. If you're writing classes in namespace mine, then your swap function also goes in namespace mine.
[edit] I misread Chaos' post
Again, sorry for off-topic:
I believe, though I could be wrong, that most video game consoles (at least on the 360 and ps3) have poor exception support, so most game programmers (who are generally targeting at least one of those platforms) don't use exceptions.That's odd, because I've been encouraged to use exceptions if it makes sense. There's an entire section on when and when not to use exceptions here: http://www.parashift.com/c++-faq-lite/exceptions.htmlhis is off topic, but: in 99% of the C++ projects I've worked on, exceptions have been banned by the programming guidelines/standards
Writing exception-safe code is very important if you're writing the standard library that will be used by everyone, but in my own experience, it's not something that is required in order to work on most C++ projects.
Yeah, there's a lot of historic reasons why exceptions in C++ aren't popular. When writing in other languages, I definitely follow the kind of guidelines you mention about when to use exceptions... but in C++ I'm usually simply not allowed to use them.
Compared to other languages, C++ exceptions also have the caveat that you often throw by value and catch by reference, in order to avoid memory management issues. In C# on the other hand, you'd use new to create the exception, and it would later be garbage collected.
In C++ this creates some rare issues, such as if you want to store a polymorphic exception -- e.g. if an exception results in a thread terminating, you'd likely want to clone it and then propagate it to the creating thread, re-throwing the exception there when it waits for completion / joins...
In the past, C++ compilers have done a pretty poor job of implementing exceptions. On PPC (consoles) it's been especially bad, with the console SDKs often encouraging you to use the command-line options to disable exceptions altogether. Even most x86 implementations aren't the best, though x86-64 has improved things.
Depending on the implementation, simply having exceptions enabled adds a lot of bloat to every single function, which is an expense you pay for regardless of whether you even throw or not. On machines with small instruction caches (e.g. old consoles), this was especially bad, and it completely violates the whole justification that "exceptions are free unless you throw".
This wasn't just in the games industry either, many other "embedded systems" fared just as poorly as games consoles.
Also on games consoles and embedded systems, there's often not much you can do in cases where an unexpected error occurs. You've got code there to deal with the expected errors, but if something unforeseen happens, often you only option is to log the error / make a debug dump and then crash hard / reboot. If this is your strategy, there will be other platform-specific ways to install a crash handler that are more effective / performant.
C++ compilers often also have two different exception handling mechanisms. e.g. MSVC has try/catch and __try/__except... The former catches things that are thrown by the programmer, and the latter catches things that are reported by the kernel, like invalid memory accesses. In C# on the other hand, all errors are handled by the standard try/catch/finally keywords. The lack of a finally in C++ also forces you to use RAII, instead of having the option to reconcile manual resource management with exception handling.
Then there's the added complexity required when writing exception-safe code. There's 4 levels -- no-throw, strong (nothing will break if an exception is thrown), weak (nothing will leak if an exception is thrown, but data might become invalid) and none (no promises, throw at your own risk).
Perfectly reusable C++ code (such as the standard library) should ideally have strong exception safety. However, writing C++ code is already complex, and writing strongly-exception-safe code makes it even more complex. In every single function you need to keep in mind what the state of you invariants will be at each line of the program, and make sure that members/data/etc are only used in a read-process-commit fashion at all times.
Simply choosing to only provide the weak guarantee by using RAII for all resources reduces the burden on the programmer. Choosing to not give any guarantees reduces it much further.
If you know for certain that a function will only ever exit at the end or at a return statement, it's much easier to analyse / mentally-debug your code.
When doing a cost benefit analysis, many companies have decided that the benefits that C++ exceptions bring do not outweigh the added costs to code authoring and maintenance and/or performance (on certain systems).
This then has a knock-on effect for library authors. If you know that some percentage of your clients are disabling support for the throw/catch keywords in their compilers, and you want to keep those customers, then you've got to remove the usage of throw/catch from your library (or make it optional). There's also a legacy effect, where if you're reusing a ton of code with no exception safety guarantees, then it's dangerous to decide to begin adding exceptions later on...
The end result of this in my experience has been a decade of writing C++ code without very much professional experience at all with C++ exceptions. It's still something that's good to have an academic grip on though
However, writing C++ code is already complex, and writing strongly-exception-safe code makes it even more complex.
To be fair, writing such code isn't just an issue where exceptions are used. Writing code without involving exceptions, that can just as equally fail to acquire resources for the same reasons, needs about as much work to ensure correctness.
This is for everyone really, a summary as to why copy & swap should be used over manually assigning:
I get the idea of copy and swap, but you're really just offloading the work to the copy ctor, aren't you? You could just as easily write the code into the assignment operator and then write the copy ctor to just call the assignment operator. If you're copying resources then you have to write the explicit copy behaviors somewhere.
The bottom line is: There are more pro's than con's for a copy&swap over the traditional method.