Avoid needless copies with move semantics and rvalue references, then apply the idioms that shape real C++: copy-and-swap, non-copyable types, Pimpl, and CRTP.
Copying duplicates an object’s resources; moving steals them, leaving the source empty — much cheaper for things like vectors and strings. An rvalue reference (T&&) binds to temporaries the compiler knows are expiring. std::move casts an lvalue to an rvalue so its resources can be pilfered.
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> src{"a", "b", "c"};
std::vector<std::string> copy = src; // duplicates all 3 strings
std::vector<std::string> moved = std::move(src); // steals the buffer; O(1)
std::cout << copy.size() << "\n"; // 3
std::cout << moved.size() << "\n"; // 3
std::cout << src.size() << "\n"; // 0 — src was moved from
return 0;
}The copy-and-swap idiom writes one correct assignment operator by copying the argument and swapping — automatically exception-safe and self-assignment-safe. When copying makes no sense (a mutex, a unique resource), delete the copy operations to make the type non-copyable and catch misuse at compile time.
#include <utility>
class Handle { // non-copyable, movable
int fd_ = -1;
public:
explicit Handle(int fd) : fd_(fd) {}
Handle(const Handle&) = delete; // no copying
Handle& operator=(const Handle&) = delete;
Handle(Handle&& o) noexcept : fd_(o.fd_) { o.fd_ = -1; } // movable
Handle& operator=(Handle&& o) noexcept {
std::swap(fd_, o.fd_); // swap: old resource dies with 'o'
return *this;
}
};Pimpl (pointer to implementation) hides a class’s data behind an opaque pointer so its header stays stable and compiles fast. CRTP (Curiously Recurring Template Pattern) has a class inherit from a template of itself, giving static (compile-time) polymorphism with no vtable cost — common in high-performance libraries.
#include <iostream>
// CRTP: Base calls into Derived without any virtual dispatch
template <typename Derived>
struct Printable {
void print() const {
std::cout << static_cast<const Derived*>(this)->text() << "\n";
}
};
struct Hello : Printable<Hello> {
const char* text() const { return "hello"; } // resolved at compile time
};
int main() {
Hello{}.print(); // hello — no vtable involved
return 0;
}