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