咨询C++11中强制对象仅可移动的代码实现是否正确
嘿,你的CResource类实现强制仅支持移动语义的方式是正确的,但CAcquireResource里的AcquireResource返回右值引用的写法有坑,咱们一步步说:
1. CResource的实现没问题
你把拷贝构造和拷贝赋值运算符放在private域并标记为= delete,这确实能完全阻止外部代码对CResource对象进行拷贝操作——因为外部无法访问private成员,就算是友元也没法调用被delete的函数。
另外,显式声明移动构造和移动赋值运算符是个好习惯:虽然如果你的类成员都是可移动的,编译器会自动生成默认的移动操作,但显式声明能明确表达你的设计意图,也方便后续自己扩展移动逻辑(比如手动管理m_pResource的转移)。
不过有个小优化建议:可以把delete的拷贝操作放到public域里,这样外部代码尝试拷贝时,编译器会直接提示“函数已删除”,比因为private访问权限报错更直观,效果完全一样:
class CResource { public: CResource(); CResource(CResource &&); CResource & operator=(CResource &&); // 直接在public区标记删除,可读性更好 CResource(const CResource &) = delete; CResource & operator=(const CResource &) = delete; private: void * m_pResource; };
2. CAcquireResource的AcquireResource写法有风险
返回CResource &&这种右值引用要格外小心,因为引用本身不持有对象的所有权。如果你的AcquireResource函数是这样实现的:
CResource && CAcquireResource::AcquireResource() { CResource res; // 初始化res... return std::move(res); }
那函数结束后,局部对象res会被销毁,返回的右值引用就变成了悬垂引用,后续使用这个引用会导致未定义行为。
正确的做法是直接返回CResource对象:
class CAcquireResource { public: CResource AcquireResource(); };
编译器会自动触发返回值优化(RVO),直接在调用方的内存空间构造对象,完全避免拷贝或移动操作;就算RVO没生效,编译器也会自动把返回的局部对象转为右值,调用移动构造函数,效率同样很高,而且不会有悬垂引用的问题。
总结一下:你的核心思路(禁用拷贝、开放移动)是对的,只是返回右值引用的地方需要调整成返回对象本身。
内容的提问来源于stack exchange,提问作者nearproc

