Using Vector with Move-Only Types
Can I use std::vector with move-only types like std::unique_ptr?
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.
Basic Usage
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 destroyedConsiderations
- Use
std::move()with theemplace_back()orpush_back()methods: Sincestd::unique_ptris move-only, you need to useemplace_back()orpush_back()withstd::move()to add elements. - Avoid copy operations:
std::vectormay need to reallocate and move its elements when it grows. Ensure your move-only types have efficient move constructors and move assignment operators. - Be cautious with reallocation: When
std::vectorreallocates, it moves all its elements. This is fine forstd::unique_ptr, but could be problematic for other move-only types that have side effects when moved. - Be careful with algorithms: Some standard algorithms may not work with move-only types. Always check the requirements of algorithms you plan to use.
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);Example with Custom Move-Only Type
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 destroyedThis 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.
Dynamic Arrays using std::vector
Explore the fundamentals of dynamic arrays with an introduction to std::vector