Non-copyable elements in vector
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.
Non-copyable elements in a std::vector of std::lists
std::list
is not noexcept-movable, but is copyable. Therefore, std::vector
prefers list
's the copy-constructor over its move-constructor, regardless.
To work around the issue, you have to wrap your std::list
in a class that is not copyable.
Using vectors with classes that contain non-copyable data types
You might try using a vector of pointers to your objects. It is better to use some kind of smart pointer, rather than a vector of raw pointers.
i.e.
std::vector< std::shared_ptr< MyClass >> MyVector;
now you have a container of pointers to MyClass objects.
How to contruct non-copyable, non-moveable class in a nested vector?
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.
In place construction of a pair of nonmovable, non copyable in a std::vector
std::vector
is subject to reallocation once the size reach the capacity.
when reallocating the elements into a new memory segment std::vector has to copy/move the values from the old segment and this is made by calling copy/move constructors.
if you don't need that the elements are sequential in memory you can use std::deque
instead, since std::deque
doesn't reallocate the elements internally.
you can't store non copyable and non moveable objects into std::vector
s.
EDIT suggested by @François Andrieux
In case you still need for any reason an std::vector
you may think to use a vector made using std::unique_ptr<X>
as value type using std::vector<std::unique_ptr<X>>
.
With this solution you still don't get a sequential order in memory of your elements, and they are keep in memory till they are still in the vector, so except in case you are forced by any reason to use std::vector
s, i think the best match is still the std::deque
.
How to create a vector with non-copyable and non-assignable objects?
std::unique_ptr
is not copyable, so you need to move it into the container:
for (int i = 0; i < 10; i++) {
auto a = MakeUnique<A>();
a->SetValue(20);
objects.emplace_back(std::move(a));
}
C++ container with non-copyable non-movable element type
Here's a simple, yet incomplete solution under the assumption that each element is constructed with the same arguments. It uses placement new
to construct the elements in-place (see also this SO question):
#include <cstdlib>
#include <utility>
#include <new>
// sample structure, non-copyable, non-moveable, non-default-constructible
struct Foo
{
Foo() = delete;
Foo(const Foo&) = delete;
Foo& operator = (const Foo&) = delete;
Foo(Foo&&) = delete;
Foo& operator = (Foo&&) = delete;
Foo(int a, char b, double c) : m_a(a), m_b(b), m_c(c) { }
int m_a;
char m_b;
double m_c;
};
template <typename T>
struct MyArray
{
// Array ctor constructs all elements in-place using the
// provided parameters
template <typename... Args>
MyArray(std::size_t sz, Args&&... args)
: m_sz(sz),
m_data(static_cast<T*>(malloc(sz * sizeof(T))))
{
for (std::size_t i=0; i<m_sz; ++i)
{
new (&m_data[i]) T(std::forward<Args>(args)...);
}
}
~MyArray()
{
for (std::size_t i=0; i<m_sz; ++i)
{
m_data[i].~T();
}
free(m_data);
}
std::size_t m_sz;
T *m_data;
};
int main()
{
Foo foo(1, '2', 3.0);
std::size_t s = 5;
MyArray<Foo> foo_arr(s, 1, '2', 3.0);
}
Note that a few things are missing:
- This basic implementation will leak memory if an exception is thrown inside
MyArray
's constructor. - You will probably want an iterator implementation,
begin()
/end()
operators etc., for more convenience and to get the same behaviour as provided by the standard containers. - For illustration's sake I also didn't bother with proper encapsulation. You should probably make
m_sz
andm_data
private members.
std::for_each over a vector of non-copyable objects
Your lambda capture block attempts to capture the whole vector by value. This is unnecessary, since the access to the elements is granted through the reference argument.
Try this:
std::vector<std::thread> threads;
std::for_each(threads.begin(), threads.end(), [](std::thread & t){t.join();});
Using vectors of non-copyable objects
Store a pointer instead. std::unique_ptr<sf::RenderWindow>
should be suitable. Initialize it with new
or std::make_unique<sf::RenderWindow>
(C++14).
Note that your main loop will need to be radically different as you would need to poll several windows. pollEvent
is unsuitable as it blocks: if you call it on wnd1
, you won’t be able to process events arriving to other windows until some event arrives to wnd1
as well.
Related Topics
Random Output Different Between Implementations
Rvalue to Lvalue Conversion Visual Studio
Why Sizeof(Int) Is Not Greater Than -1
Do You (Really) Write Exception Safe Code
Insert VS Emplace VS Operator[] in C++ Map
How to See the Assembly Code for a C++ Program
Can the Use of C++11's 'Auto' Improve Performance
Std::Auto_Ptr to Std::Unique_Ptr
What Would Be C++ Limitations Compared C Language
How Boost::Function and Boost::Bind Work
Pimpl Idiom VS Pure Virtual Class Interface
Passing Shared Pointers as Arguments
What Does "Operator = Must Be a Non-Static Member" Mean
Specialization of Templated Member Function in Templated Class
How to Immediately Invoke a C++ Lambda
I Want a Vector of Derived Class Pointers as Base Class Pointers