3 ms·
Post C++11, it is probably better to use the "copy and move" idiom. MyClass& operator=(const MyClass& other) { return (*this) = MyClass(other);
by jbandela1 4y ago
Post C++11, it is probably better to use the "copy and move" idiom.
MyClass& operator=(const MyClass& other) {
return (*this) = MyClass(other);
}
- vlovich123 4y agoIn any version of the language it's better to decompose it so that you never implement any of these. You either have: 1. A class that's responsible for managing exactly one instance of a resource (e.g. FileDescriptor). This class defines whether or not a resource is copyable and/or movable. 2. A dynamically sized container that needs to offer certain kinds of guarantees. 3. A composite class that may contain zero or more instances of 1, 2, and/or 3. The vast majority of classes you write are always going to be 3. Option 3 should NEVER specify move/copy constructors/assignment operators and instead should inherit that from whatever is being stored. Don't do #2 unless you really know what you're doing. Prefer to use existing well-behaved containers from STL. If you need 3p ones, Folly and Boost are probably good ones. I don't know how ABSEIL fares around exception safety when exceptions are enabled so YMMV there if you're doing things in an exception context. It can be hard to properly make sure that you inherit the copyability / movability from the underlying type (& also noexcept inheritance). For #1, KISS is a very good principle. Just make sure you always leave resources in a consistent state. Move helps here a lot but can be emulated with copy + swap pre-C++11. Here's an example of what a copyable and movable resource might look like: // Terrible idea - don't actually do this in practice. class AutoDupOnCopyFd { public: AutoDupOnCopyFd(const AutoDupOnCopyFd& copy): _fd(dup(copy._fd)) { if (_fd == -1) { throw ... } } AutoDupOnCopyFd(AutoDupOnCopyFd&& owned) noexcept: _fd(std::exchange(copy._fd, -1)) {} ~AutoDupOnCopyFd() noexcept { close(_fd); } AutoDupOnCopyFd& operator=(const AutoDupOnCopyFd& other) { // No need to check for assignment to self but you can if you think you're likely to have this happen // to avoid the syscall (copy to self is typically rare) AutoDupOnCopyFd copy(other); *this = *copy; return *this; } AutoDupOnCopyFd& operator=(AutoDupOnCopyFd&& other) noexcept { using std::swap; swap(_fd, other._fd); return *this; } private: int _fd; }; Now `AutoDupOnCopyFd` can be nested in any composite class & the composite class will automatically inherit the right set of copy / move semantics with correct exception safety. The rule of 0 really is a powerful concept. This breaks down if you start trying to make 1 class responsible for multiple resources. Don't do that. Use resource classes + containers/composite classes to do that. You can also (ab)use unique_ptr for unique ownership although I still prefer explicitly named classes (no confusion with `->` vs `.`, easier to understand for the vast majority of coders). It's a powerful concept to internalize to level up your C++ game but it's only applicable to C++'s ownership model. Rust went a more teachable path that doesn't have these foot guns.
- bbqbbqbbq 4y ago> I don't know how ABSEIL fares around exception safety when exceptions are enabled so YMMV there if you're doing things in an exception context OMG this is my time to shine. I wrote the library for testing Abseil containers for exception-safety. I don't work there anymore but I know they've implemented exception safety tests for a bunch of containers in there, and I remember when I was writing the library we even found a bug in GNU `std::optional`. https://www.youtube.com/watch?v=XPzHNSUnTc4 https://www.youtube.com/watch?v=XPzHNSUnTc4 is the talk I gave at cppCon about this. As a side story, that talk was the first one in the morning and I showed up just before it started on account of my Uber driver missing the highway exit. I had planned to grab some food at the conference but didn't have time so that whole talk I was overstimulated on coffee on an empty stomach trying to keep my composure early in the morning.
- vlovich123 4y agoI'm kind of surprised that ABSEIL even bothers with exception safety since Google builds everything without exceptions. Can you shed some light on why the team decided to invest in making it exception safe?
- its_bbq 4y agoBecause many of the OSS projects using Abseil do use exceptions and that code, as you pointed out, was completely untested with exceptions on.