Porting code from C ++ 03 to C ++ 11: should I be careful about the implicit default move constructor?

I have some code that I would like to switch from C ++ 03 to C ++ 11.

As I understand it, some classes will benefit from the change, having an implicit default move constructor (and the move destination operator that comes along). While I totally agree with this (I even think it's good), I'm a little scared of the effects that such implicit constructors may have for some disjoint classes that I have.

In one example, I have a class that wraps the iconv_t descriptor from libiconv to use RAII.

More specifically, the class is as follows:

 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; }; 

It bothers me: if an instance of this class is ported, this will result in a double call to iconv_close() . Since iconv_t is a "mute" integral type, I do not expect the default implementation of iconv_wrapper(iconv_wrapper&&) to invalidate the m_iconv member of R. Even if that happened, the destructor would not be implemented to work correctly.

So my questions are:

  • Are my problems legal? Is it correct that the default movable constructor / operator = will be incorrect in this case?
  • What changes can I make to port this code well in C ++ 11? (I was offered std::unique_ptr , but I could not do this job beautifully, since it expects a pointer, not some opaque type)
+6
source share
1 answer

He will not be moved. Since you have a declared copy constructor, the copy assignment operator and destructor, the move constructor, and the move destination operator will not be generated. In fact, either of these three would declare the suppression of the automatic generation of the motion constructor and the motion destination operator.

If you want to make it more C ++ 11 friendly, you can add a move constructor and move the assignment operator, as in (warning: never compiled or tested):

 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; }; 

The reason you want to do this is to save these objects (or other types containing these objects) in a vector.

+9
source

All Articles