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.
Related
I have a class Foo with no sensible default constructor. I would also prefer to keep the copy-assignment operator private, although that may become impossible. (I'd like to make the class “almost” immutable, whence thread-safe, by having const fields and the small number of mutators that cast const way as private and early in the object lifetime.)
Creating std::vector<Foo> under these constraints is a little bit of a challenge. I came up with a solution I haven't seen elsewhere (see, for example, earlier SO question 1). I have a custom iterator which, when dereferenced, creates a Foo. It is set up such that each invocation increments to the next value of Foo in the vector. The sequence is easy to define. I define operator++, next, advance, distance and operator* on CustomIterator.
Then I have
std::vector<Foo> foo_vec{CustomIterator(0), CustomIterator(size_of_vector)};
No access issues. No unnecessary constructions. No copies. Anyone see a problem with this?
I will summarize the comments. The simple factory generates vector of initialized elements.
#include <vector>
class X {
explicit X(int value) : value_(value) {}
X& operator=(const X&) = default;
friend std::vector<X> generate(int from, int to);
public:
const int value_;
};
// simplest factory ever
std::vector<X> generate(int from, int to) {
std::vector<X> result;
result.reserve(to - from);
for (int k = from; k < to; ++k) {
result.emplace_back(std::move(X(k)));
}
return std::vector<X>();
}
int main() {
auto v = generate(0, 10);
static_cast<void>(v);
}
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);
I have a class which needs to have a std::unordered_set which holds non-copyable, non-moveable entity objects, and whose hash function hashes the instance's address. Something like the following:
class A
{
public:
A();
A(const A&) = delete;
A(A&&) = delete;
void operator=(const A&) = delete;
void operator=(A&&) = delete;
bool operator==(const A& other) { return this == &other; }
};
template<>
struct std::hash<A>
{
size_t operator()(const A& obj) const
{
return std::hash<A*>()(&obj);
}
};
class B
{
private:
std::unordered_set<A> entities;
};
If emplace() is always used instead of insert(), is it safe to use unordered_set in this way? Does the standard specify that an implementation can't move node objects after they are constructed?
What about if A were moveable? Is it guaranteed that the hash function will be called on the object owned by the set, or since the standard library prefers to think of everything as value-objects, is it allowed to hash an inserted object before storage is allocated for it?
As a final thought, I know I could get around all this by using std::unordered_set<std::unique_ptr<A>>, but I'd like to use a custom allocator for the A objects, and I don't want to override new and delete for A.
Using the address of an object as a hash pretty much guarantees that you won't find the object unless you already hold a pointer to the object other than iteration through the hash. You'll need to come up with a different approach to get a hash from your object. That said, once consructed inside the hash the object's address won't change.
I still think you are better off using a std::list. Consider:
#include <iostream>
#include <list>
class A
{
public:
int i_;
A(int i) : i_(i) {}
A(const A&) = delete;
A(A&&) = delete;
void operator=(const A&) = delete;
void operator=(A&&) = delete;
};
int main()
{
std::list< A > l;
// inserting elements
auto it1 = l.emplace( l.end(), 1 ); // note: complexity is O(1)
auto it2 = l.emplace( l.end(), 2 );
auto it3 = l.emplace( l.end(), 3 );
auto it4 = l.emplace( l.end(), 4 );
// deleting an element by iterator
l.erase( it2 ); // note: complexity is O(1)
// note: it2 is now invalid
// accessing element by iterator
it3->i_ = 42;
for( const auto& e : l ) {
std::cout << e.i_ << std::endl;
}
// silence compiler warnings
(void)it1;
(void)it4;
}
In the above, all your use-cases should have an efficient implementation. You can avoid the overhead of calculating the hash and having the hash-map. It's even more efficient as your hash-based approach, for the list both operations are O(1) and much more light-weigth wrt the implementation. And storing the iterator is not much different from storing a pointer to the element directly.
Also, it is guaranteed that this works for non-copyable and non-movable types. See the documentation for std::list::emplace.
As Dietmar mentions, once constructed, the value's address can't change. As far as the second part of the question, the standard seems to not only allow, but require implementations to call the hash/equal_to functors on an object passed to insert() by reference, rather than requiring the construction of a node first and calling the functions on that object:
From 23.2.5 Table 103 — Unordered associative container requirements
pair<iterator, bool> a_uniq.insert(t)
Effects: Inserts t if and only if there is no element in the container with key equivalent to the key of t.
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);
}
};
See the code below - I am trying to put a const object into a vector. I know the answer is "STL containers require objects to be assignable and copy constructable", but, without citing the standard, can anyone explain what the problem with doing this is? I don't understand why a class like this could not be copied (besides that c++ doesn't allow it).
All it is is a value stored that is not allowed to be changed - why can't putting it in a vector simply create another one of these objects?
#include <vector>
// Attempt 1
// /home/doriad/Test/Test.cxx:3:8: error: non-static const member ‘const int MyClass::x’, can’t use default assignment operator
// struct MyClass
// {
// int const x;
// MyClass(int x): x(x) {}
// };
//
// int main()
// {
// std::vector<MyClass> vec;
// vec.push_back(MyClass(3));
// return 0;
// }
// Attempt 2
// /home/doriad/Test/Test.cxx:28:23: error: assignment of read-only member ‘MyClass::x’
struct MyClass
{
int const x;
MyClass(int x): x(x) {}
MyClass& operator= (const MyClass& other)
{
if (this != &other)
{
this->x = other.x;
}
return *this;
}
};
int main()
{
std::vector<MyClass> vec;
vec.push_back(MyClass(3));
return 0;
}
EDIT:
It is possible to do this with std::set and std::list. I guess it is the sort() function in std::vector that uses assignment. This is not UB right?
#include <set>
// Attempt 1
struct MyClass
{
int const x;
MyClass(int x): x(x) {}
bool operator< (const MyClass &other) const;
};
bool MyClass::operator<(const MyClass &other) const
{
if(this->x < other.x)
{
return true;
}
else if (other.x < this->x)
{
return false;
}
}
int main()
{
std::set<MyClass> container;
container.insert(MyClass(3));
return 0;
}
EDIT2: (Removing a bunch of stuff that doesn't have to work) The C++11 standard states that the insert method for vector and deque (and the default implementation of push_back for that matter) requires the value type to be CopyAssignable, i.e., the value supports:
t= v;
Classes and structs with const members are not CopyAssignable by default, so what you want to do won't work.
This doc (n3173) has an explanation for the various container requirements.
One possible solution would be to store pointers to the objects in the vector, because pointers are assignable and copy constructable.
Another possible solution would be to declare x without the const keyword, but ensure that it cannot be modified through encapsulation (i.e. you should declare it as private and don't modify from anywhere outside the constructor)..
When you place an object of type MyClass in the std::vector, the vector will make a copy of the object for storage, and not the object you passed to it.