Emplacing in vector using default constructor
Solution 1
As pointed out by @dyp and @Casey in the comments, std::emplace
will not work for vectors of the Test class as the class is also not movable because "the user-declared copy constructor suppresses generation of the default move constructor" (@Casey).
To use emplace
here, the class will need to be movable. We can do this by explicitly defining (and defaulting) the move constructors:
public:
Test(Test&& other) = default;
Test& operator=(Test&& other) = default;
This will also implicitly make the class not-copyable "since declaring the move operations will suppress implicit generation of the copies." (@Casey)
Now we can use std::emplace_back()
and then use vector::back()
to call methods of the newly created object.
Solution 2
vector::emplace_back()
will construct at the end of the vector but also require arguments.
Parameter packs can be empty. Thus the variadic template emplace_back
can be called without arguments; I.e.
vector<VeryLimitedClass> vec;
vec.emplace_back();
Is valid code that initializes an object of type VeryLimitedClass
through its default constructor and "emplaces" it at the back of vec
.
Related videos on Youtube
Chizzy C
Updated on June 26, 2022Comments
-
Chizzy C almost 2 years
I want to use
vector::emplace
to default construct a non-copyable and non-assignable object and then use specific methods on the object using an iterator to the newly created object. Note that there are no parameterized constructors of the class just the default constructor. A simple example is:#include <iostream> #include <vector> using namespace std; class Test { public: Test() {} private: Test(const Test&) = delete; // To make clas un-copyable. Test& operator=(const Test&) = delete; int a_; }; int main() { vector<Test> test_vec; test_vec.emplace_back(); // <---- fails return 0; }
vector::emplace()
constructs a new object but requires arguments to a non-default constructor.vector::emplace_back()
will construct at the end of the vector.Is there a way to emplace with default construction. Is there a way to use piecewise construction or default forwarding perhaps using
std::piecewise_construct
as there is for maps? For example, in the case of maps, we can use:std::map<int,Test> obj_map; int val = 10; obj_map.emplace(std::piecewise_construct, std::forward_as_tuple(val), std::forward_as_tuple());
Is there something similar for vectors?
-
Columbo over 9 years@dyp ... you know exactly what I meant. I don't want to confuse the OP with standard terminology. :)
-
dyp over 9 yearsInterestingly, there's no guarantee what kind of initialization is happening neither from the vector nor from the allocator requirements. But yes, it probably doesn't care much. -- I haven't upvoted this answer since I'm not sure if we already know the whole picture. If the OP has a noncopyable AND nonmovable type,
emplace
cannot be used. -
Columbo over 9 years@dyp Are you sure about the first part of your last comment?
-
dyp over 9 yearsI know that I wanted to report a defect since more than a year IIRC relating to that (and vector's exception safety guarantees). I have looked quite thoroughly into this issue at that time.
-
dyp over 9 yearsE.g. if we look at the allocator requirements, it only guarantees that an object of the specified type is created; it does not say anything about the arguments or the form of initialization. -- Preliminary version of the allocator construction problem: groups.google.com/a/isocpp.org/d/topic/std-discussion/…
-
Casey over 9 yearsWe can say with certainty that the default allocator will perform value-initialization per [allocator.members]/12, which says the effect of
construct(U* p, Args&&... args)
is equivalent to::new((void *)p) U(std::forward<Args>(args)...)
. But we can't say with certainty that the default allocator is in use without seeing the entire translation unit, even knowing the type of the vector isstd::vector<VeryLimitedClass>
, sincestd::allocator<VeryLimitedClass>
may be a user-defined specialization.