如何安全提取非空bar类的std::unique_ptr成员,避免对象意外失效?
安全实现bar到baz的数据转移,避免bar无效化
核心思路
利用C++的右值引用成员函数限定特性,只允许对右值状态的bar对象执行数据提取操作。右值bar代表对象即将被销毁(或用户明确要转移其资源),此时提取数据不会导致有效状态的bar变成空指针,从编译层面直接阻止误用。
具体实现
1. 修改bar类,添加右值限定的提取函数
struct foo {}; class bar { public: bar(std::unique_ptr<foo> data) : data{ std::move(data) } { if (!this->data) { throw std::invalid_argument{ "Unexpected null pointer" }; } } foo* get_data() { return data.get(); } // 仅右值bar可调用的提取函数 std::unique_ptr<foo> extract_data() && { return std::move(data); } private: std::unique_ptr<foo> data; };
2. 实现merge_data函数(两种可选方式)
方式一:全局merge_data函数
class baz { public: baz() = default; void add_data(std::unique_ptr<foo> data) { vec.push_back(std::move(data)); } private: std::vector<std::unique_ptr<foo>> vec; }; void merge_data(baz& target, bar&& source) { // 仅能对右值source调用extract_data target.add_data(std::move(source).extract_data()); }
方式二:将merge_data作为baz的成员函数
class baz { public: baz() = default; void add_data(std::unique_ptr<foo> data) { vec.push_back(std::move(data)); } void merge_data(bar&& source) { add_data(std::move(source).extract_data()); } private: std::vector<std::unique_ptr<foo>> vec; };
安全机制说明
- 编译层面阻止误用:如果尝试对左值bar(正常使用中的对象)调用
extract_data(),编译器直接报错:bar valid_bar{std::make_unique<foo>()}; valid_bar.extract_data(); // 编译失败!左值无法调用右值限定的成员函数 - 语义明确:只有当bar是右值(临时对象或被
std::move显式标记为可转移的对象)时,才能提取其数据,此时用户清楚知晓资源会被转移,不会误以为是拷贝操作。 - 维护类约束:bar的
data永远不会在有效生命周期内变为空指针,严格遵守了"bar必须始终处于有效状态"的设计要求。
使用示例
int main() { baz my_baz; // 临时bar对象(右值)直接合并 my_baz.merge_data(bar{std::make_unique<foo>()}); // 显式转移左值bar的所有权(用户明确知晓) bar temp_bar{std::make_unique<foo>()}; my_baz.merge_data(std::move(temp_bar)); // 此时temp_bar资源已被转移,语义上不再有效,不应继续使用 }
内容的提问来源于stack exchange,提问作者Involute
相关产品推荐
相关产品推荐

