vector of class without default constructor - c++

Consider the following class:
Class A
{
public:
A() = delete;
A(const int &x)
:x(x)
{}
private:
int x;
};
How can one create an std::vector<A> and give an argument to the constructor A::A(const int&)?

How can I create a std::vector of type A and give an argument to A's constructor?
std::vector<A> v1(10, 42); // 10 elements each with value 42
std::vector<A> v2{1,2,3,4}; // 4 elements with different values
How would I add 3 to the vector?
v.emplace_back(3); // works with any suitable constructor
v.push_back(3); // requires a non-explicit constructor
The lack of a default constructor only means you can't do operations that need one, like
vector<A> v(10);
v.resize(20);
both of which insert default-constructed elements into the vector.

Templates are not instantiated in one go : they only instantiate what is needed. A satisfies all the conditions for the following (constructing an empty vector) to be valid :
std::vector<A> v;
However, as A does not have a default constructor, the following (creating a vector with default-initialized content) would fail :
std::vector<A> v(100);
And that's a good thing. However, valid methods will be instantiated fine :
v.emplace_back(42);

The trick is in how you add elements into the vector and what member functions of the vector you use.
std::vector<A> v;
v.emplace_back(3);

Related

How to contruct non-copyable, non-moveable class in a nested vector?

I want to construct a vector using a non-default constructor of a non-copyable, non-movable class. With the default constructor it works fine, and I can construct a vector, as long as I don't resize it. But somehow with a non-default constructor it seems to have to copy. Does anyone know if I can avoid the copy operation during construction with a non-default constructor so I can keep using vector?
#include <vector>
#include <mutex>
class A {
public:
A(int num) : vec(num) {}
private:
std::vector<std::mutex> vec;
};
class B {
public:
B(int numB, int numA) : vec(numB, numA) {}
private:
std::vector<A> vec;
};
int main() {
B b(2, 3);
return 0;
}
When I try to compile this I get:
/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range
You can use std::vector<std::mutex> directly, because the type requirements when using standard library containers are restricted to only those required by the functions called on them.
Once you have constructed a std::vector<std::mutex> with some elements, only the operations that might add new elements or erase old ones require the value type to be movable. Accessing the vector elements and moving the vector itself are not problems.
Constructing the vector with vec(num) works, because it only default constructs a known number of elements. It can constructs the new elements in-place in the storage.
The constructor used by vec(numB, numA) actually takes as arguments the number of elements and a const lvalue reference to an object of the value type. It does not take constructor arguments to construct the new elements from in-place. Instead when you pass it numA, numA is implicitly converted to a A (via the non-explicit constructor) and a reference to that A is passed to the constructor.
The constructor is then specified to copy-construct the vector elements from the passed object.
But because std::vector<std::mutex> vec; is not copyable, A isn't either and so it fails.
There is however another constructor for std::vector that can construct objects without copy/move constructor: The constructor taking an iterator range. However, to use it we first need to construct an iterator range with the constructor arguments to pass to the vector elements' constructor:
auto args = std::vector(numB, numA);
vec = {args.begin(), args.end()};
Alternatively, with explicit types:
std::vector<int> args(numB, numA);
vec = std::vector<A>(args.begin(), args.end());
If you want to do this in the member-initilizer-list you can delegate this to a member function or lambda and return instead of vec =.
The iterator range constructor construct the vector elements in-place by converting *it and if the iterators are forward iterators (as is the case above), then the constructor does not require any move operations.
Note that vec.assign(args.begin(), args.end()) does not work, since assign is allowed to use assignment instead of construction.

Is it possible to store an object which contains a unique_ptr in a static container?

I'd like to store an object that contains a unique_ptr in a static container:
Class A
{
public:
A() {}
~A() {}
private:
unique_ptr<int> p;
};
static vector<A> vec = { A() };
But the code fails to compile, as class A is not copyable due to the unique ptr.
How can I solve this, without having to define a copy constructor in class A that would perform a move operation on the pointer?
Unfortunately, it won't compile as written. When list-initializing (with a {...}) a std::vector, the constructor called is the one with std::initializer_list, and it doesn't allow move semantics.
There are workarounds, but its kind of ugly
static auto vec = []{
std::vector<A> vec;
vec.emplace_back();
return vec;
}();
Live
First of all, by defining the destructor, you will lose the automatically generated move-constructor. So you either have to remove it or define a proper move constructor. Then, you can initialize it as easy as
static vector<A> vec(1);
If you want to prevent objects of type A from being copyable, then the only way I see is to use a vector of shared_ptr<A>. Not sure if this meets your requirements or your intent, but at least it works:
static vector<shared_ptr<A>> vec = { make_shared<A>() };

Why doesn't this use of emplace_back with deleted copy constructor work?

I have a type that I have deleted the copy constructor from, and I would like to have a vector of this type, so I need to create all the elements via emplace_back. But, emplace_back seems to require a copy constructor, as the compiler gives a warning about not being able to instantiate emplace_back because the copy constructor has been deleted. Why does it need a copy constructor? I thought the whole point of emplace_back was to build the vector without copying anything. Can I even have a vector of objects that don't have a copy constructor?
class MyType {
public:
MyType(std::array<double, 6> a) {}
MyType(const MyType& that) = delete;
};
int main() {
std::vector<MyType> v;
std::array<double, 6> a = {1,2,3,4,5,6};
v.emplace_back(a);
}
Compiler is clang/llvm.
When the vector's internal storage grows, it will need to move the elements from the old storage to the new. By deleting the copy constructor, you also prevent it generating the default move constructor.
To be able to call emplace_back, your type should either be EmplaceConstructible or MoveInsertible .
You need to give a move constructor to your class if you have deleted the copy constructor. (Check this for requirements of emplace_back)
MyType(MyType &&a) {/*code*/} //move constructor
If you try to run this code:
// Example program
#include <iostream>
#include <string>
#include <array>
#include <vector>
class MyType {
public:
MyType(std::array<double, 6> a) {
std::cout<< "constructed from array\n";
}
MyType(const MyType& that){
std::cout<< "copy\n";
}
MyType(MyType&& that){
std::cout<< "move\n";
}
};
int main() {
std::vector<MyType> v;
std::array<double, 6> a = {1,2,3,4,5,6};
v.emplace_back(a);
}
You will get the following result:
constructed from array
Live Demo
It is clear that just the constructor from std::Array is called. So, no need for copy constructor. But in the same time if you deleted the copy constructor, the compiler will raise an error (at least on two compilers I tried first second ). I think that some compilers will check for the existence of copy constructor when using emplace_back even if it is not necessary in this practical case while others won't. I do not know what is standard here (which compiler is right or wrong).

Calling non default template constructor in a Class constructor

Is it possible in the following example to call the "not default constructor" of class A for every element of mVector within the constructor of class B ?
class A {
public:
A (int n) {/*stuff*/}
};
class B {
public:
B (): mVector(10) {} //call A(int n) constructor?
private:
vector<A> mVector;
};
If you want to set all the elements to the same value, there's a constructor for that
mVector(10, 42) // 10 elements initialised with value 42
If you want to set the elements to different values, use list initialisation
mVector{1,2,3,4,5,6,7,8,9,10} // 10 elements with different values
Strictly speaking, this doesn't do exactly what you describe; it creates a temporary T, and then uses that to copy-initialise each vector element. The effect should be the same, unless your type has weird copy semantics.
You could do one thing here:-
B() : mVector(10, A(10))
{
}
Or
B() : mVector(10, 10)
{
}
Both are essentially the same thing. However, former one is more efficient.
You can use the constructor overload of std::vector taking an element count and a value which for your use case is equivalent to:
std::vector(size_type count, const T& value);
Use it to initialize the elements with the value type's non default constructor:
std::vector<A> mVector(10, A{0}); // 10 elements copy initialized using 'A{0}'.
Or when initializing in the initialization list:
B() : mVector(10, A{0}) {}

Initializing a std::vector with default constructor

I have a class field which is a std::vector. I know how many elements I want this vector to contain: N. How do I initialize the vector with N elements?
std::vector has a constructor declared as:
vector(size_type N, const T& x = T());
You can use it to construct the std::vector containing N copies of x. The default value for x is a value initialized T (if T is a class type with a default constructor then value initialization is default construction).
It's straightforward to initialize a std::vector data member using this constructor:
struct S {
std::vector<int> x;
S() : x(15) { }
}
class myclass {
std::vector<whatever> elements;
public:
myclass() : elements(N) {}
};
All the constructors that allow you to specify a size also invoke the element's constructor. If efficiency is paramount, you can use the reserve() member function to reserve the size. This does not actually create any elements, so it is more efficient. In most cases, though, supplying the size through the vector constructor is just fine.