Как иметь дело с noncopyable объектами при вставке в контейнеры в C++

Я ищу лучшую практику контакта с объектами non-copyable.

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

Это взломало код - некоторые места просто должны были быть зафиксированы, но у меня есть универсальная проблема, где класс, с помощью взаимного исключения или как элемента данных, или наследованием, вставляется в контейнер.

Это обычно происходит во время контейнерной инициализации, таким образом, взаимное исключение еще не инициализируется и поэтому в порядке, но без конструктора копии это не работает. Изменение контейнеров для содержания указателей не приемлемо.

Кто-либо советует?

12
задан dbbd 11 August 2010 в 10:44
поделиться

8 ответов

Если объект нельзя копировать, то обычно на это есть веская причина. И если для этого есть веская причина, вам не следует разрушать это, помещая его в контейнер, который пытается его скопировать.

4
ответ дан 2 December 2019 в 06:07
поделиться

Если они не копируемые, контейнер должен хранить (интеллектуальные) указатели на эти объекты или ссылочные оболочки и т. Д., Хотя с C ++ 0x некопируемые объекты все еще могут быть перемещаемыми ( как потоки boost), чтобы их можно было хранить в контейнерах как есть.

, чтобы привести примеры: эталонная оболочка (также известная как boost :: ref, указатель под капотом)

#include <vector>
#include <tr1/functional>
struct Noncopy {
private:
        Noncopy(const Noncopy&) {}
public:
        Noncopy() {}
};
int main()
{
        std::vector<std::tr1::reference_wrapper<Noncopy> > v;
        Noncopy m;
        v.push_back(std::tr1::reference_wrapper<Noncopy>(m));
}

C ++ 0x, протестирован с помощью gcc:

#include <vector>
struct Movable {
private:
        Movable(const Movable&) = delete;
public:
        Movable() {}
        Movable(Movable&&) {}
};
int main()
{
        std::vector<Movable> v;
        Movable m;
        v.emplace_back(std::move(m));
}

EDIT: Nevermind, C ++ 0x FCD говорит, ниже 30.4 .1 / 3,

Тип Mutex не может быть копируемым или перемещаемым.

Так что вам лучше иметь указатели на них. Смарт или иным образом завернутый по мере необходимости.

4
ответ дан 2 December 2019 в 06:07
поделиться

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

2
ответ дан 2 December 2019 в 06:07
поделиться

Использование мьютекса в классе не обязательно означает, что класс не должен быть копируемым. Вы можете (почти) всегда реализовать это так:

C::C (C const & c)
// No ctor-initializer here.
{
  MutexLock guard (c.mutex);

  // Do the copy-construction here.
  x = c.x;
}

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

0
ответ дан 2 December 2019 в 06:07
поделиться

Лучший вариант - использовать указатели или какой-либо тип класса-оболочки, который использует указатели под капотом. Это позволило бы их разумно скопировать и фактически делать то, что ожидается от копии (совместно использовать мьютекс).

Но, поскольку вы сказали, что указателей нет, есть еще один вариант. Похоже, что мьютексы «иногда копируются», возможно, вам следует написать конструктор копирования и оператор присваивания, чтобы они генерировали исключение, если мьютекс когда-либо копируется после его инициализации. Обратной стороной является то, что нет никакого способа узнать, что вы делаете что-то неправильно, до времени выполнения.

1
ответ дан 2 December 2019 в 06:07
поделиться

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

Некоторые говорили о том, что объекты можно перемещать, и об использовании C ++ 0x, в котором контейнеры часто требуют, чтобы их элементы были перемещаемыми, но не требуют, чтобы они были копируемыми. Я думаю, что это также плохое решение, потому что я подозреваю, что мьютексы не следует перемещать, пока они удерживаются, и это делает фактически невозможным их перемещение.

Итак, единственный реальный оставшийся ответ - указать на мьютексы. Используйте :: std :: tr1 :: shared_ptr #include ) или :: boost :: shared_ptr , чтобы указать на мьютексы . Это требует изменения определений классов, в которых есть мьютексы, но похоже, что вы все равно это делаете.

2
ответ дан 2 December 2019 в 06:07
поделиться

Используйте интеллектуальные указатели, такие как boost :: shared_ptr, или другие контейнеры, например boost :: intrusive. Оба потребуют изменения вашего кода через.

1
ответ дан 2 December 2019 в 06:07
поделиться

Здесь три решения:

1. Use Pointers - Быстрое решение - сделать его контейнером указателей, например a shared_ptr .

Это было бы «хорошим» решением, если ваши объекты действительно не копируются и использование других контейнеров невозможно.

2. Другие контейнеры . В качестве альтернативы вы можете использовать не копирующие контейнеры (которые используют построение на месте), однако они не очень распространены и в значительной степени несовместимы с STL.(Я пробовал какое-то время, но это просто бесполезно)

Это было бы "божественным" решением, если ваши объекты действительно не копируются, и использование указателей невозможно.

[править] В C ++ 13 std :: vector допускает создание на месте (emplace_back) и может использоваться для некопируемых объектов, которые реализуют семантику перемещения. [/ править]

3. Исправьте вашу копируемость - Если ваш класс копируемый как таковой, а мьютекс - нет, вам «просто» нужно исправить конструктор копирования и оператор присваивания.

Писать их сложно, так как обычно вам приходится копировать и назначать все элементы, кроме мьютекса, но это часто можно упростить, выполнив следующие действия:

template <typename TNonCopyable>
struct NeverCopy : public T 
{
    NeverCopy() {}
    NeverCopy(T const & rhs) {}

    NeverCopy<T> & operator=(T const & rhs) { return *this; }
}

И изменив свой член мьютекса на

NeverCopy<Mutex> m_mutex;

К сожалению, используя этот шаблон, вы теряете специальные конструкторы Mutex.

[править] Предупреждение: «Фиксация» CTor / asignment копирования часто требует, чтобы вы заблокировали правую часть конструкции копирования и заблокировали обе стороны при назначении. К сожалению, нет способа переопределить ctor / assignment копирования и вызвать реализацию по умолчанию, поэтому трюк NeverCopy может не сработать для вас без внешней блокировки. (Есть и другие обходные пути со своими ограничениями.)

11
ответ дан 2 December 2019 в 06:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: