I have two classes, one derive from the other. I would like to allocate an std:vector which is fill of the derived class. The tricky question is that I want it to call the move constructor written in the base class.
Here is the code:
class Base{
public:
size_t size;
double* buff;
Base(size_t _size):size(_size){
buff = new double[size];
}
Base() = delete;
Base operator=(const Base&) = delete;
Base(const Base&) = delete;
Base(Base&& b):size(b.size), buff(b.buff){
b.buff = nullptr;
}
Base operator=(Base&& b){
size = b.size;
buff = b.buff;
b.buff = nullptr;
}
};
class Derive : public Base{
public:
Derive(size_t _size):Base(_size){};
Derive() = delete;
Derive operator=(const Derive&) = delete;
Derive(const Derive&) = delete;
Derive(Derive&& b):Base(move(b)){}
Derive operator=(Derive&& b){
Base::operator=(move(b));
}
};
/********/
vector<Derive> v(10, move(Derive(5)));
g++ is telling me
error: use of deleted function ‘Derive::Derive(const Derive&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
and I don't understand what I am supposed to do.
The problem here is that std::vector(count, object) copies object, count times, into the vector. You cannot move from it since you can only move an object into a single object.
If your class is not copyable then you will not be able to use it. You can however use
std::vector<Type> foo;
foo.reserve(count);
for (int i = 0; i < count; ++i)
foo.emplace_back(Types_parmeters);
You are trying to build a vector of 10 elements from one single source. This is not possible because once the source element has been moved once, it is left in an undeterminated state.
For that reason, this constructor is specified in draft n4296 for C++14 to use the copy constructor (emphasize mine):
23.3.6.2 vector constructors, copy, and assignment [vector.cons]
...vector(size_type n, const T& value,
const Allocator& = Allocator());
Effects: Constructs a vector with n copies of value, using the specified allocator.
Requires: T shall be CopyInsertable into *this.
...
An alternative solution is to write your own version of fill_n that can handle this use case. The typical fill_n does copies the same as the vector constructor, but we can write a more modern style one.
template <class T, class OutputIt, class Size, class .. Args>
OutputIt emplace_fill_n(OutputIt first, Size count, const Args& ... args)
{
for (Size i = 0; i != count; ++i) {
*first = T(args...);
++first;
}
}
Usage:
vector<Derive> v();
v.reserve(10);
emplace_fill_n<Derive>(back_inserter(v), 10);
Related
I know that std vectors can work with objects that are not default constructible. However, when I try to implement a slightly modified one myself, I cant seem to make such vector.
class A
{
public:
A() = delete;
A(const int &x)
:x(x)
{}
private:
int x;
};
template <typename T, int N> //default constructor of the vector
CircularBuffer<T,N>::CircularBuffer()
{
Size = 0;
Capacity =N;
Array = new T[Capacity];
Start = 0;
End = 0;
}
template <typename T, int N>
CircularBuffer<T,N>::CircularBuffer(const CircularBuffer& rhs) //copy constructor of the vector
{
Size = rhs.Size;
Capacity = rhs.Capacity;
Array = new T[Capacity];
Start = rhs.Start;
End = rhs.End;
for(int i=0;i<Capacity;i++)
{
this->Array[i] = rhs.Array[i];
}
}
template <typename T, int N> //move constructor of the vector
CircularBuffer<T,N>::CircularBuffer(CircularBuffer&& rhs)
{
rhs.Swap(*this);
}
template <typename T, int N>
void CircularBuffer<T,N>:: Swap(CircularBuffer &source)
{
swap(Size,source.Size);
swap(Capacity,source.Capacity);
swap(Start,source.Start);
swap(End,source.End);
swap(Array,source.Array);
}
When I try to make a vector with object A,
CircularBuffer<A,3> v;
error: use of deleted function ‘A::A()’
I get this error which is obviously self explanatory. Anyone can help me solve this??
The problem is here
Array = new T[Capacity];
which default constructs T objects.
std::vector uses placement new to construct objects when they are added to the vector.
Array = (T*)operator new(sizeof(T)*Capacity);
and (when you add the new item)
new(Array + i) T(...); // placement new
where ... are the arguments you wish to pass to the constructor.
See here for more details.
The issue is with the line Array = new T[Capacity];. This needs to default-initialize all members of the array, which it cannot do without a default-constructor.
std::vector gets around it by splitting allocation and construction with its allocator. I recommend you simply use std::allocator as well. Otherwise you can use placement-new to construct the elements after allocating the required memory separately.
I'm implementing a ring buffer container class:
template <class T, class A = std::allocator<T>>
class ring {
private:
size_type cap_; // the capacity of the array
alloc_type alloc_; // the allocator
pointer array_;
...
public:
ring(size_type n, const alloc_type &a = alloc_type()) : cap_{n}, alloc_{a}, array_{alloc_.allocate((size_t)cap_)}, ... {
memset(array_, 0, (size_t)cap_ * sizeof(T));
}
...
};
(I have not shown the typedefs here, but they're obvious.)
I'm not sure how to write the (deep) copy constructor so that it handles the allocator correctly, but I imagine that the copy must have its own allocator (of the same type), and then I'd loop through the original allocated array and copy element by element.
Would it be something like this?:
ring(const self_type& r) : cap_{r.cap_}, ... {
alloc_ = ??? // not sure what to do here
array_ = alloc_.allocate((size_t)cap_);
for (size_type i{}; i < r.size(); ++i) {
alloc_.construct(array_[i], r.array_[i]);
}
}
ring(const self_type& r)
: alloc_(std::allocator_traits<alloc_type>::
select_on_container_copy_construction(r.alloc_)) {
}
See also: AllocatorAwareContainer
For writing a template list class, the equivalent of vector (purely as a design exercise) I am trying to find out what is done to be efficient.
If one writes:
v = new T[size];
then the compiler will call the constructor for T, right? T().
So instead in the class below:
v = (T*) new char[sizeof(T) * size]
This seems easy enough. However, in the destructor, how to delete just the ones that have been initialized? In the following class, only the first "used" elements are initialized.
Also, in the copy constructor, how to call the copy constructor for T for only the used elements efficiently?
If I initialized the expensive way, it works:
v = new T[size];
for (int i = 0; i < used; i++)
v[i] = orig.v[i];
but that requires that v already be intiialized with T(). What is the better way?
Class is below:
#include <cstdint>
template<typename T>
class List {
private:
uint32_t used;
uint32_t capacity;
T* v;
public:
List(uint32_t cap) : used(0), capacity(cap), v((T*)new char[sizeof(T)*capacity]) {}
~List() {
delete [] v; // no
}
List(const List& orig) : used(orig.used), capacity(orig.capacity), v((T*) new char[sizeof(T)*capacity]) {
// now copy only the used ones
for (int i = 0; i < used; i++)
v[i] = orig.v[i]; // no, operator = will call destructor on v[i], but it is uninitialized
}
};
To be like std::vector, you need to use "placement new" and explicitly call destructors.
#include <new>
~List() {
while (used) {
--used;
v[used]->~T();
}
delete[] reinterpret_cast<char*>(v);
}
List(const List& orig) : used(orig.used), capacity(orig.capacity),
v(reinterpret_cast<T*>(new char[sizeof(T)*capacity])) {
// now copy only the used ones
for (int i = 0; i < used; i++)
new(v+i) T(orig.v[i]);
}
Note the above copy constructor is not exception-safe. Try to make it so.
First, just use std::vector<T> instead of reimplementing this yourself.
What you're looking for here is placement new and explicit destructor calls. Where normally, each new should be paired with a delete, each placement new should be paired with an explicit destructor call.
To answer your specific questions:
However, in the destructor, how to delete just the ones that have been initialized?
Explicitly call their destructors, then delete[] the original char[] allocation correctly, which will (correctly) not automatically call any T destructors.
for (uint32_t i = 0; i < used; ++i) {
v[i]->~T();
}
delete [] reinterpret_cast<char *>(v);
Also, in the copy constructor, how to call the copy constructor for T for only the used elements efficiently?
You need to placement-new here. Your line v[i] = orig.v[i]; causes undefined behavior because v[i] has not yet been constructed.
Placement-new the objects instead (which you should do to each v[i] before you use it):
new(reinterpret_cast<char *>(v + i)) T(orig.v[i]);
For in the copy constructor you can try this code:
#include <cstring>
List(const List& orig) : used(orig.used), capacity(orig.capacity), v((T*) new char[sizeof(T) * capacity]) {
// now copy only the used ones
memcpy(v, orig.v, sizeof(T)*capacity);
}
or
List(const List& orig) : used(orig.used), capacity(orig.capacity), v((T*) new char[sizeof(T) * capacity]) {
// now copy only the used ones
memcpy_s(v, capacity, orig.v, sizeof(T)*capacity);
}
I have a non-copyable class (i.e. the copy constructor & assignment operator are marked as 'delete'). I would like to keep these in a std::vector.
It is a RAII class so simply storing the pointer or reference to it is not what I am looking for.
My knowledge of the new initialiser lists & move constructors is somewhat limited, is this possible?
Yes you can have std::vector<NotCopyable> if NotCopyable is movable:
struct NotCopyable
{
NotCopyable() = default;
NotCopyable(const NotCopyable&) = delete;
NotCopyable& operator = (const NotCopyable&) = delete;
NotCopyable(NotCopyable&&) = default;
NotCopyable& operator = (NotCopyable&&) = default;
};
int main()
{
std::vector<NotCopyable> v;
NotCopyable nc;
v.push_back(NotCopyable{});
v.emplace_back();
v.push_back(std::move(nc));
}
Live example.
As long as the elements are movable then, yes, simply store them in the vector.
Is there a standard container for a sequence of fixed length, where that length is determined at runtime. Preferrably, I'd like to pass an argument to the constructor of each sequence element, and use that argument to initialize a const member (or a reference). I'd also like to obtain the sequence element at a given index in O(1). It seems to me that all of my requirements cannot be met at the same time.
I know std::array has fixed length, but that length has to be known at compile-time.
std::vector has dynamic size, and allows passing contructor arguments using emplace. Although you can reserve memory to avoid actual reallocations, the type still has to be movable to theoretically allow such reallocations, which e.g. prevents const members.
Then there is std::list and std::forward_list, which don't require a movable type, but which are still resizable and will perform rather poorly under random-access patterns. I also feel that there might be considerable overhead associated with such lists, since each list node will likely be allocated separately.
Strangely enough, std::valarray is my best bet so far, since it has a fixed length and won't resize automatically. Although there is a resize method, your type won't have to be movable unless you actually call that method. The main deficit here is the lack for custom constructor arguments, so initializing const members isn't possible with this approach.
Is there some alternative I missed? Is there some way to adjust one of the standard containers in such a way that it satisfies all of my requirements?
Edit: To give you a more precise idea of what I'm trying to do, see this example:
class A {
void foo(unsigned n);
};
class B {
private:
A* const a;
const unsigned i;
public:
B(A* aa) : a(aa), i(0) { }
B(A* aa, unsigned ii) : a(aa), i(ii) { }
B(const std::pair<A*, unsigned>& args) : B(args.first, args.second) { }
B(const B&) = delete;
B(B&&) = delete;
B& operator=(const B&) = delete;
B& operator=(B&&) = delete;
};
void A::foo(unsigned n) {
// Solution using forward_list should be guaranteed to work
std::forward_list<B> bs_list;
for (unsigned i = n; i != 0; --i)
bs_list.emplace_front(std::make_pair(this, i - 1));
// Solution by Arne Mertz with single ctor argumen
const std::vector<A*> ctor_args1(n, this);
const std::vector<B> bs_vector(ctor_args1.begin(), ctor_args1.end());
// Solution by Arne Mertz using intermediate creator objects
std::vector<std::pair<A*, unsigned>> ctor_args2;
ctor_args2.reserve(n);
for (unsigned i = 0; i != n; ++i)
ctor_args2.push_back(std::make_pair(this, i));
const std::vector<B> bs_vector2(ctor_args2.begin(), ctor_args2.end());
}
Theoretically vector has the properties you need. As you noted, actions that possibly do assignments to the contained type, including especially any sequence modifications (empace_back, push_back, insert etc.) are not supported if the elements are noncopyable and/or nonassignable. So to create a vector of noncopyable elements, you'd have to construct each element during vector construction.
As Steve Jessop points out in his answer, if you define the vector const in the first place you won't even be able to call such modifying actions - and of course the elements remain unchanged as well.
If I understand correctly, you have only a sequence of constructor arguments, not the real object sequence. If it's only one argument and the contained type has a corresponding constructor, things shoule be easy:
struct C
{
const int i_;
C(int i) : i_(i) {}
};
int main()
{
const std::vector<C> theVector { 1, 2, 3, 42 };
}
If the constructor is explicit, you have to make a list first or explicitly construct the objects in the initializer-list:
int main()
{
auto list = { 1, 2, 3, 4 };
const std::vector<C> theVector (std::begin(list), std::end(list));
const std::vector<C> anotherVector { C(1), C(44) };
}
If it's more than just one argument per constructed object, consider a intermediate creator object:
struct C
{
const int i_;
C(int i, int y) : i_(i+y) {}
};
struct CCreator
{
int i; int y;
explicit operator C() { return C(i,y); }
};
int main()
{
const std::vector<CCreator> ctorArgs = { {1,2}, {3,42} };
const std::vector<C> theVector { begin(ctorArgs), end(ctorArgs) };
}
I think const std::vector<T> has the properties you ask for. Its elements aren't actually defined with const, but it provides a const view of them. You can't change the size. You can't call any of the member functions that need T to be movable, so for normal use they won't be instantiated (they would be if you did an extern class declaration, so you can't do that).
If I'm wrong, and you do have trouble because T isn't movable, try a const std::deque<T> instead.
The difficulty is constructing the blighter -- in C++11 you can do this with an initializer list, or in C++03 you can construct a const vector from a non-const vector or from anything else you can get iterators for. This doesn't necessarily mean T needs to be copyable, but there does need to be a type from which it can be constructed (perhaps one you invent for the purpose) .
Add a level of indirection by using a std::shared_ptr. The shared pointer can be copied and assigned as usual, but without modifying the object that is pointed to. This way you should not have any problems, as the following example shows:
class a
{
public:
a(int b) : b(b) { }
// delete assignment operator
a& operator=(a const&) = delete;
private:
// const member
const int b;
};
// main
std::vector<std::shared_ptr<a>> container;
container.reserve(10);
container.push_back(std::make_shared<a>(0));
container.push_back(std::make_shared<a>(1));
container.push_back(std::make_shared<a>(2));
container.push_back(std::make_shared<a>(3));
Another advantage is the function std::make_shared which allows you to create your objects with an arbitrary number of arguments.
Edit:
As remarked by MvG, one can also use std::unique_ptr. Using boost::indirect_iterator the indirection can be removed by copying the elements into a new vector:
void A::foo(unsigned n)
{
std::vector<std::unique_ptr<B>> bs_vector;
bs_vector.reserve(n);
for (unsigned i = 0; i != n; ++i)
{
bs_vector.push_back(std::unique_ptr<B>(new B(this, i)));
}
typedef boost::indirect_iterator<std::vector<std::unique_ptr<B>>::iterator> it;
// needs copy ctor for B
const std::vector<B> bs_vector2(it(bs_vector.begin()), it(bs_vector.end()));
// work with bs_vector2
}
I also encounter this problem, the use case in my code is to provide a thread-safe vector, the elements number is fixed and are atomic numbers. I have read all the great answers here. I think we may also consider my solution:
Just inherited the std::vector and hide the modifiers such as push_back, emplace_back, erase, then we get a fixed size vector. We can only access and modify the elements with operator [].
template <typename T>
class FixedVector : protected std::vector<T> {
public:
using BaseType = std::vector<T>;
FixedVector(size_t n) : BaseType(n) {}
FixedVector(const T &val, size_t n) : BaseType(val, n) {}
typename BaseType::reference operator[](size_t n) {
return BaseType::operator[](n);
}
};