Yes, you can use std::vector
with move-only types like std::unique_ptr
. However, there are some important considerations and best practices to keep in mind.
Here's a simple example of using std::vector
with std::unique_ptr
:
#include <iostream>
#include <vector>
#include <memory>
class Resource {
public:
Resource(int id) : id(id){
std::cout << "Resource " << id <<
" created\n";
}
~Resource(){
std::cout << "Resource " << id <<
" destroyed\n";
}
int getId() const{ return id; }
private:
int id;
};
int main(){
std::vector<std::unique_ptr<Resource>>
resources;
// Adding elements
resources.push_back(
std::make_unique<Resource>(1));
resources.emplace_back(
std::make_unique<Resource>(
2)); // Accessing elements
for (const auto& resource : resources) {
std::cout << "Resource ID: "
<< resource->getId() << '\n';
}
// Vector will automatically delete the
// Resources when it goes out of scope
}
Resource 1 created
Resource 2 created
Resource ID: 1
Resource ID: 2
Resource 2 destroyed
Resource 1 destroyed
std::move()
with the emplace_back()
or push_back()
methods: Since std::unique_ptr
is move-only, you need to use emplace_back()
or push_back()
with std::move()
to add elements.std::vector
may need to reallocate and move its elements when it grows. Ensure your move-only types have efficient move constructors and move assignment operators.std::vector
reallocates, it moves all its elements. This is fine for std::unique_ptr
, but could be problematic for other move-only types that have side effects when moved.Additionally, to minimize reallocations, consider using reserve()
if you know how many elements you'll be adding:
std::vector<std::unique_ptr<Resource>> resources;
// Prepare space for 10 elements
resources.reserve(10);
Here's an example with a custom move-only type:
#include <iostream>
#include <vector>
#include <utility>
class MoveOnlyType {
public:
MoveOnlyType(int value) : value(value){
std::cout << "MoveOnlyType " << value <<
" created\n";
}
MoveOnlyType(const MoveOnlyType&) = delete;
MoveOnlyType& operator=(const MoveOnlyType&)
= delete;
MoveOnlyType(MoveOnlyType&& other) noexcept
: value(other.value){
std::cout << "MoveOnlyType " << value <<
" moved\n";
other.value = 0;
}
MoveOnlyType& operator=(
MoveOnlyType&& other) noexcept{
if (this != &other) {
value = other.value;
other.value = 0;
std::cout << "MoveOnlyType " << value
<< " move assigned\n";
}
return *this;
}
~MoveOnlyType(){
std::cout << "MoveOnlyType " << value <<
" destroyed\n";
}
int getValue() const{ return value; }
private:
int value;
};
int main(){
std::vector<MoveOnlyType> vec;
vec.reserve(3);
// Avoid reallocation for this example
vec.push_back(MoveOnlyType(1));
vec.emplace_back(2);
vec.push_back(std::move(MoveOnlyType(3)));
for (const auto& item : vec) {
std::cout << "Value: " << item.getValue() <<
'\n';
}
}
MoveOnlyType 1 created
MoveOnlyType 1 moved
MoveOnlyType 0 destroyed
MoveOnlyType 2 created
MoveOnlyType 3 created
MoveOnlyType 3 moved
MoveOnlyType 0 destroyed
Value: 1
Value: 2
Value: 3
MoveOnlyType 1 destroyed
MoveOnlyType 2 destroyed
MoveOnlyType 3 destroyed
This example demonstrates creating, moving, and destroying move-only objects within a std::vector
. Understanding these concepts is crucial when working with move-only types in containers like std::vector
.
Answers to questions are automatically generated and may not have been reviewed.
std::vector
Explore the fundamentals of dynamic arrays with an introduction to std::vector