Почему unique_pointer решает ошибку “нет подходящей функции для вызова ‘construct_at'”?

Вопрос или проблема

У меня есть класс с мьютексом:

Class StoreNumbers{
  StoreNumbers();
  AddNumber(size_t number){
    const std::lock_guard<std::mutex> lock(lock_);
    numbers_.push_back(number);
  }

  private:
  std::mutex lock_;
  std::vector<size_t> numbers_;

};

Цель класса — возможность хранить числа при использовании в многопоточном контексте. Несомненно, есть лучшие способы сделать это, но это иллюстрирует мой вопрос.

Теперь я хочу иметь различные объекты этих классов, чтобы хранить разные типы чисел. Я также хочу, чтобы каждый из этих типов имел свой собственный мьютекс, так как они не связаны между собой.

Если я пишу:

std::vector<StoreNumbers> vec;
vec.push_back(StoreNumber());

Я получаю ошибку компилятора: no matching function for call to ‘construct_at’, что я понимаю, поскольку мьютекс нельзя копировать.

Если вместо этого я использую:

std::unique_ptr<std::mutex> lock_=std::make_unique<std::mutex>();

для блокировки и разыменовываю его для lock_guard, я больше не получаю ошибку. Я не понимаю, почему. Спасибо за помощь!

Ответ или решение

Ошибка "no matching function for call to ‘construct_at’" возникает в вашем коде из-за попытки копирования нестандартных объектов, таких как std::mutex, в стандартные контейнеры, как std::vector.

Когда вы пытаетесь создать вектор объектов типа StoreNumbers, компилятор пытается создать временные копии, чтобы разместить их в векторе. Однако, std::mutex не поддерживает операцию копирования, ибо это приводит к неопределённому поведению в многопоточном окружении, что было подсознательно задумано разработчиками библиотеки C++. Таким образом, когда вы вызываете vec.push_back(StoreNumber());, происходит попытка копии объекта, содержащего std::mutex, что и вызывает ошибку.

Теперь рассмотрим, почему использование std::unique_ptr<std::mutex> исправляет эту ситуацию. При замене std::mutex на std::unique_ptr<std::mutex> в вашем классе StoreNumbers, вы меняете стратегию управления ресурсами. std::unique_ptr позволяет динамически выделять память для std::mutex, управляя её жизненным циклом. Эта конструкция является копируемой вектором, так как std::unique_ptr поддерживает перемещение, а не копирование.

Когда вы делаете следующее:

std::unique_ptr<std::mutex> lock_ = std::make_unique<std::mutex>();

Вы обеспечиваете создание нового объекта std::mutex в динамической памяти, который управляется указателем. При этом, при операции добавления в вектор, вместо копирования объекта, происходит перемещение указателя на std::mutex. То есть, место в памяти, в котором находится std::mutex, не копируется, а передаётся управление. Таким образом, каждая новая инстанция StoreNumbers, хранится в векторе с уникальным, отдельно выделенным mutex. Это предотвращает любые проблемы, связанные с копированием, и устраняет возникшую ранее ошибку компиляции.

Этот подход не только исправляет ошибку, но и повышает гибкость и безопасность вашего многопоточного кода. Поскольку каждый StoreNumbers теперь имеет свой собственный экземпляр std::mutex, код становится более безопасным и эффективным для параллельного выполнения.

Такое управление ресурсами и интеграция уникальных указателей является стандартом хорошей практики в современном C++. Это помогает избегать ошибок и утечек памяти, обеспечивая более безопасный и чистый код, особенно в многоуровневом программировании.

Таким образом, использование std::unique_ptr не только устраняет ошибку компиляции, но и улучшает архитектуру вашего приложения, сделав его более безопасным и понятным.

Оцените материал
Добавить комментарий

Капча загружается...