Миграция кода с C++03 на C++11: должен ли я быть осторожен с неявным конструктором перемещения по умолчанию?

у меня есть кодовая база, которую я хотел бы переключить с C++03 на C++11.

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

один пример у меня есть класс, который обертывает в iconv_t ручка от libiconv чтобы использовать RAII.

более эксплицитно, класс выглядит следующим образом:

class iconv_wrapper
{
   public:
     iconv_wrapper() : m_iconv(iconv_open()) {}
     ~iconv_wrapper() { iconv_close(m_iconv); }
   private:
     // Not implemented: non copyable. Should probably be = delete; in C++11.
     iconv_wrapper(const iconv_wrapper&);
     iconv_wrapper& operator=(const iconv_wrapper&);

     iconv_t m_iconv;
};

меня беспокоит: если экземпляр этого класса был перемещен, это приведет к двойному вызову iconv_close(). As iconv_t является" тупым " интегральным типом, я не ожидаю реализации по умолчанию iconv_wrapper(iconv_wrapper&&) обнулить m_iconv член R-значения. Даже если это так, деструктор не реализован для правильной обработки этого.

Итак, мои вопросы являются:

  • являются ли мои опасения законными ? Я прав, что подвижный конструктор/оператор= по умолчанию будет неправильным в таком случае ?
  • какие изменения я могу внести, чтобы красиво перенести этот код на C++11 ? (Мне предложили std::unique_ptr но я не мог сделать эту работу красиво, так как он ожидает указатель, а не какой-то непрозрачный тип)

1 ответов


Он не будет перемещен. Поскольку у вас есть объявленный пользователем конструктор копирования, оператор назначения копирования и деструктор, конструктор перемещения и оператор назначения перемещения не будут созданы. Фактически, любой из этих трех объявленных будет подавлять автоматическую генерацию конструктора перемещения и оператора назначения перемещения.

Если вы хотите сделать его более удобным для C++11, вы можете добавить конструктор перемещения и оператор назначения перемещения, как в (предупреждение: никогда не компилируется или проверено):

class iconv_wrapper
{
   public:
     iconv_wrapper() : m_iconv(iconv_open()) {}
     ~iconv_wrapper() { if ((iconv_t)-1 != m_iconv) iconv_close(m_iconv); }
     iconv_wrapper(iconv_wrapper&& that) noexcept { std::swap(m_iconv, that.m_iconv); }
     iconv_wrapper& operator=(iconv_wrapper&& that) noexcept { std::swap(m_iconv, that.m_iconv); return *this; }

   private:
     iconv_t m_iconv = (icontv_t)-1;
};

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