C++ implicitly provides up to six special member functions: default constructor, destructor, copy constructor, copy assignment operator, move constructor, and move assignment operator (the latter two since C++11). The following example logs when each is invoked.
#include <iostream>
struct Resource {
Resource() : id(0) { std::cout << "Default ctor @" << this << ", id=" << id << '\n'; }
Resource(int val) : id(val) { std::cout << "Int ctor @" << this << ", id=" << id << '\n'; }
~Resource() { std::cout << "Dtor @" << this << ", id=" << id << '\n'; }
Resource(const Resource& other) : id(other.id) {
std::cout << "Copy ctor @" << this << ", id=" << id << '\n';
}
Resource& operator=(const Resource& other) {
id = other.id;
std::cout << "Copy assign @" << this << ", id=" << id << '\n';
return *this;
}
#if __cplusplus >= 201103L
Resource(Resource&& other) : id(other.id) {
other.id = -1;
std::cout << "Move ctor @" << this << ", id=" << id << '\n';
}
Resource& operator=(Resource&& other) {
id = other.id;
other.id = -1;
std::cout << "Move assign @" << this << ", id=" << id << '\n';
return *this;
}
#endif
int id;
};
void demonstrate_constructors() {
std::cout << "\n// Resource a(5);\n";
Resource a(5);
std::cout << "\n// Resource b(a);\n";
Resource b(a);
std::cout << "\n// Resource c = a;\n";
Resource c = a;
std::cout << "\n// c = a;\n";
c = a;
#if __cplusplus >= 201103L
std::cout << "\n// Resource d(std::move(a));\n";
Resource d(std::move(a));
std::cout << "\n// d = std::move(a);\n";
d = std::move(a);
#endif
}
Output shows that std::move enables move semantics by casting to an rvalue reference.
Placement new allows in-place construction, commonly used in container implementations like std::vector::emplace_back. The placement form of operator new simply returns the provided pointer:
inline void* operator new(std::size_t, void* ptr) noexcept { return ptr; }
Example usage:
#include <new>
struct Widget {
Widget(int x) : value(x) {}
int value;
};
int main() {
void* buffer = ::operator new(sizeof(Widget));
Widget* w = ::new (buffer) Widget(42);
w->~Widget();
::operator delete(buffer);
}
At the assembly level, the memory address from operator new becomes the this pointer passed to the constructor.
std::move and std::forward are utilities introduced in C++11 to manage value categories:
std::move<T>(x)castsxto an rvalue reference (T&&), enabling move operations.std::forward<T>(x)preserves the value categroy ofxin template contexts via reference collapsing rules.
Example:
template<typename T>
void wrapper(T&& arg) {
Resource item(std::forward<T>(arg));
}
Resource src(10);
wrapper(src); // copy
wrapper(std::move(src)); // move
wrapper(Resource(20)); // move (temporary)
In STL containers, constructor behavior depends on the operation and C++ standard version.
For std::vector<Resource>:
push_back(Resource(5))in C++98 invokes the int constructor and copy constructor.- In C++11+, if the argument is an rvalue, it uses the move constructor instead.
emplace_back(5)constructs the object directly in vector storage, avoiding intermediate temporaries.
During reallocation, older standard library implementations may use copy constructors even when move constructors are available, due to iterator-based copying logic that treats elements as lvalues.
For std::map<int, Resource>:
map[key] = Resource(1)requires a default constructor for the value type (to create a placeholder) and then assignment.- Pre-C++11,
insert({key, Resource(val)})triggers multiple copies. - In C++11+, using
insert({key, Resource(val)})oremplace(key, Resource(val))leverages move semantics, reducing unnecessary copies.
The emplace family of functions forwards arguments directly to the element’s constructor via perfect forwarding, minimizing overhead.