C++ Constructor Invocation Patterns Across Different Contexts

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) casts x to an rvalue reference (T&&), enabling move operations.
  • std::forward<T>(x) preserves the value categroy of x in 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)}) or emplace(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.

Tags: C++ Constructors move semantics placement new STL

Posted on Thu, 17 Sep 2026 16:21:26 +0000 by lalomarquez