maz*_*ork 27 raii move-constructor c++11
我喜欢const成员变量的想法,特别是当我将C函数包装到类中时.构造函数获取在整个对象生命周期内保持有效的资源句柄(例如文件描述符),析构函数最终将其关闭.(那是RAII背后的想法,对吧?)
但是使用C++ 0x移动构造函数我遇到了问题.由于析构函数也在"卸载"对象上调用,我需要防止资源句柄的清理.由于成员变量是const,我无法分配值-1或INVALID_HANDLE(或等效值)来向析构函数指示它不应该执行任何操作.
有没有办法在对象的状态被移动到另一个对象时不调用析构函数?
例:
class File
{
public:
// Kind of "named constructor" or "static factory method"
static File open(const char *fileName, const char *modes)
{
FILE *handle = fopen(fileName, modes);
return File(handle);
}
private:
FILE * const handle;
public:
File(FILE *handle) : handle(handle)
{
}
~File()
{
fclose(handle);
}
File(File &&other) : handle(other.handle)
{
// The compiler should not call the destructor of the "other"
// object.
}
File(const File &other) = delete;
File &operator =(const File &other) = delete;
};
Run Code Online (Sandbox Code Playgroud)
Pup*_*ppy 18
这就是你不应该声明所述成员变量的原因const.const成员变量通常没有用处.如果您不希望用户改变它FILE*,那么不要为它们提供执行此操作的功能,如果您想阻止自己意外改变它,请标记您的功能const.但是,不要自己创建成员变量const- 因为当您开始使用移动或复制语义时,您会遇到乐趣.
不,没有办法做到这一点.我建议如果你真的附加到handle变量是const你应该有一个非const标志成员变量,指示破坏是否应该做任何事情.
其实我今天也遇到了这个问题。不愿意接受“无法完成”和“使用shared_ptr /引用计数”,谷歌搜索更多,我想出了这个基类:
class Resource
{
private:
mutable bool m_mine;
protected:
Resource()
: m_mine( true )
{
}
Resource(const Resource&) = delete;
void operator=(const Resource&) = delete;
Resource(const Resource&& other)
: m_mine( other.m_mine )
{
other.m_mine = false;
}
bool isMine() const
{
return m_mine;
}
};
Run Code Online (Sandbox Code Playgroud)
所有方法和构造函数都受保护,您需要继承它才能使用它。注意可变字段:这意味着后代可以是类中的 const 成员。例如,
class A : protected Resource
{
private:
const int m_i;
public:
A()
: m_i( 0 )
{
}
A( const int i )
: m_i( i )
{
}
A(const A&& a)
: Resource( std::move( a ) )
, m_i ( std::move( a.m_i ) ) // this is a move iff member has const move constructor, copy otherwise
{
}
~A()
{
if ( isMine() )
{
// Free up resources. Executed only for non-moved objects
cout << "A destructed" << endl;
}
}
};
Run Code Online (Sandbox Code Playgroud)
A 的字段现在可以是 const。请注意,我继承了 protected,因此用户不会意外地将 A 强制转换为资源(或者非常愿意破解它),但 A 仍然不是最终的,因此您仍然可以从中继承(从资源继承的一个有效原因是例如,具有单独的读取和读写访问权限)。这是极少数情况之一,受保护的继承并不自动意味着您的设计有缺陷;但是,如果您觉得难以理解,您可以使用公共继承。
然后,假设您有struct X:
struct B
{
const A m_a;
const X m_x;
B(const A&& a, const X& x) // implement this way only if X has copy constructor; otherwise do for 'x' like we do for 'a'
: m_a( std::move( a ) )
, m_x( x )
{
}
B( const B&& b )
: m_a( std::move( b.m_a ) )
, m_x( std::move( b.m_x ) ) // this is a move iff X has move constructor, copy otherwise
{
}
~B()
{
cout << "B destructed" << endl;
}
};
Run Code Online (Sandbox Code Playgroud)
请注意,B 的字段也可以是 const。我们的移动构造函数是常量。鉴于您的类型具有适当的移动构造函数,任何堆分配的内存都可以在对象之间共享。