3 ms·
I'm interested in the semantics of "if needed" and "constructs in place." I'm confused as to how you could initialize dynamic memory without a copy. I feel lik
by leecommamichael 2y ago
I'm interested in the semantics of "if needed" and "constructs in place."
I'm confused as to how you could initialize dynamic memory without a copy. I feel like initializing dynamic memory _is_ copying (memcpy), unless we're talking about some sort of fully constexpr thing.
- jcelerier 2y agobasically: #include <format> #include <string> #include <vector> struct my_type { std::string data; my_type(int value): data(value, 'A') { puts("int ctor\n"); } my_type() { puts("default ctor\n"); } my_type(const my_type&) { puts("copy ctor\n"); } my_type(my_type&&) noexcept { puts("move ctor\n"); } my_type& operator=(const my_type&) { puts("copy assign\n"); return *this; } my_type& operator=(my_type&&) noexcept { puts("move assign\n"); return *this; } }; int main() { puts("Case A\n"); { std::vector<my_type> vec; vec.emplace_back(123); } puts("Case B\n"); { std::vector<my_type> vec; vec.push_back(my_type{123}); } } Here, in the first case (in a very schematic way), the vector: 1/ allocates the memory for an element in for instance: my_type* mem_begin = std::allocator<my_type>::allocate(...); 2/ calls std::construct_at(&mem_begin[0], 123); which directly creates the object and calls my_type::my_type(int) constructor in the std::vector's memory storage. The only output you'll see will be int ctor The inner std::string will also be initialized directly in the right memory position, at no point there will be a copy of, say, 10000 'A' characters. In the second case, first you construct my_type on the stack of the calling code so you get a first call to my_type::my_type(int) Then my_type is moved (or copied, if it didn't have move constructors): std::vector's implementation does pretty much the same thing, but the result is two constructions instead of one: my_data* mem_begin = std::allocator<my_data>::allocate(...); ... std::construct_at(&mem_begin[0], instance_of_my_data_passed_in_argument); which ends up calling my_type::my_type(my_type&&) ; you'll see int ctor move ctor and the inner string will be copied / moved too