传递std::unique_ptr时,若仅观察则用const引用,若转移所有权则值传递并std::move,返回时也推荐值返回以实现高效所有权移交。

在C++中,将
std::unique_ptr
const std::unique_ptr<T>&amp;amp;amp;amp;
std::unique_ptr<T>
std::move
std::unique_ptr<T>
处理
std::unique_ptr
观察(Observe)对象,不转移所有权: 当函数只需要读取
unique_ptr
unique_ptr
const std::unique_ptr<T>&amp;amp;amp;amp;
void observe_object(const std::unique_ptr<MyClass>& ptr) {
if (ptr) {
ptr->do_something_const(); // 可以访问对象
// ptr = nullptr; // 编译错误:不能修改 const 引用
}
}修改(Modify)unique_ptr
unique_ptr
std::unique_ptr<T>&
ptr->
void modify_object(std::unique_ptr<MyClass>& ptr) {
if (ptr) {
ptr->do_something_non_const(); // 可以修改对象
// ptr = std::make_unique<MyClass>(); // 也可以修改 unique_ptr 本身,但通常不建议
}
}值得注意的是,这种方式也可以让函数修改
unique_ptr
release()
MyClass&
转移(Transfer)所有权给函数: 当函数需要完全接管
unique_ptr
std::unique_ptr<T>
std::move
unique_ptr
void take_ownership(std::unique_ptr<MyClass> ptr) { // 通过值接收
if (ptr) {
// 现在这个函数拥有了 MyClass 实例的所有权
ptr->process_and_store();
}
// ptr 在函数结束时自动销毁其管理的对象
}
// 调用时:
std::unique_ptr<MyClass> original_ptr = std::make_unique<MyClass>();
take_ownership(std::move(original_ptr)); // 必须使用 std::move
// 此时 original_ptr 已经为空从函数返回(Return)unique_ptr
std::unique_ptr<T>
std::unique_ptr<MyClass> create_my_object() {
// 创建一个新对象并返回其所有权
return std::make_unique<MyClass>();
}
std::unique_ptr<MyClass> process_and_transfer(std::unique_ptr<MyClass> input_ptr) {
if (input_ptr) {
input_ptr->do_some_processing();
}
// 返回所有权,可能是新的,也可能是修改过的旧的
return input_ptr; // 编译器通常会优化为移动
}
// 调用时:
std::unique_ptr<MyClass> obj1 = create_my_object();
std::unique_ptr<MyClass> obj2 = process_and_transfer(std::move(obj1));unique_ptr
const&
在我看来,这是
unique_ptr
unique_ptr
const std::unique_ptr<T>&amp;amp;amp;amp;
立即学习“C++免费学习笔记(深入)”;
想象一下,你有一个日志记录器,它需要打印某个对象的当前状态。这个日志器显然不应该获得对象的所有权,也不应该修改对象本身,它只是一个旁观者。这时候,传递
const std::unique_ptr<T>&amp;amp;amp;amp;
class DataProcessor {
public:
void process_data(const std::unique_ptr<std::string>& data_source) {
if (data_source) {
std::cout << "Processing data: " << *data_source << std::endl;
// 尝试修改 data_source 会导致编译错误,这很好
// *data_source = "new data"; // 如果 string 是 const,这里会报错
} else {
std::cout << "No data source to process." << std::endl;
}
}
void analyze_data_length(const std::unique_ptr<std::vector<int>>& numbers) {
if (numbers) {
std::cout << "Vector size: " << numbers->size() << std::endl;
// numbers->push_back(100); // 编译错误,因为 numbers 是 const 引用
}
}
};
// 使用示例
int main() {
auto my_string_ptr = std::make_unique<std::string>("Hello C++");
auto my_vector_ptr = std::make_unique<std::vector<int>>(std::initializer_list<int>{1, 2, 3});
DataProcessor processor;
processor.process_data(my_string_ptr);
processor.analyze_data_length(my_vector_ptr);
// my_string_ptr 和 my_vector_ptr 仍然有效,所有权未变
std::cout << "Original string after processing: " << *my_string_ptr << std::endl;
return 0;
}这种传递方式的优点在于:
unique_ptr
const
如果你只是想访问底层对象,甚至可以考虑直接传递底层对象的
const&
const MyClass&
unique_ptr
unique_ptr
if (ptr)
unique_ptr
const std::unique_ptr<T>&amp;amp;amp;amp;
unique_ptr
当你的函数需要“拿走”一个对象的所有权时,也就是说,这个对象从现在开始由这个函数或函数内部的某个实体来管理其生命周期,那么你就应该通过值传递
std::unique_ptr<T>
这种方式的重点在于,当
unique_ptr
unique_ptr
unique_ptr
unique_ptr
nullptr
// 假设有一个资源管理类
class ResourceManager {
public:
// 接收一个 unique_ptr,表示将资源添加到管理器中
void add_resource(std::unique_ptr<SomeResource> resource) {
if (resource) {
std::cout << "Resource " << resource->get_id() << " added to manager." << std::endl;
resources_.push_back(std::move(resource)); // 将所有权转移到 vector 中
} else {
std::cout << "Attempted to add a null resource." << std::endl;
}
}
// 假设可以根据ID查找并移除资源,并返回其所有权
std::unique_ptr<SomeResource> remove_resource(int id) {
for (auto it = resources_.begin(); it != resources_.end(); ++it) {
if (*it && (*it)->get_id() == id) {
std::cout << "Resource " << id << " removed from manager." << std::endl;
std::unique_ptr<SomeResource> removed_res = std::move(*it); // 转移所有权
resources_.erase(it);
return removed_res;
}
}
std::cout << "Resource " << id << " not found." << std::endl;
return nullptr; // 如果没找到,返回空指针
}
private:
std::vector<std::unique_ptr<SomeResource>> resources_;
};
class SomeResource {
public:
SomeResource(int id) : id_(id) { std::cout << "SomeResource " << id_ << " constructed." << std::endl; }
~SomeResource() { std::cout << "SomeResource " << id_ << " destructed." << std::endl; }
int get_id() const { return id_; }
void do_work() { std::cout << "Resource " << id_ << " doing work." << std::endl; }
private:
int id_;
};
int main() {
ResourceManager manager;
std::unique_ptr<SomeResource> res1 = std::make_unique<SomeResource>(101);
std::unique_ptr<SomeResource> res2 = std::make_unique<SomeResource>(102);
std::cout << "Before adding, res1 is " << (res1 ? "valid" : "null") << std::endl;
manager.add_resource(std::move(res1)); // 必须使用 std::move
std::cout << "After adding, res1 is " << (res1 ? "valid" : "null") << std::endl; // res1 变为空
manager.add_resource(std::move(res2)); // res2 也变为空
std::unique_ptr<SomeResource> retrieved_res = manager.remove_resource(101);
if (retrieved_res) {
retrieved_res->do_work();
}
// retrieved_res 在 main 结束时被销毁
return 0;
}关键点:
std::move
std::move
unique_ptr
std::move
std::move
unique_ptr
nullptr
unique_ptr
unique_ptr
从函数返回
std::unique_ptr
std::unique_ptr<T>
这种方式的强大之处在于,现代C++编译器通常能够执行所谓的返回值优化(RVO - Return Value Optimization)或具名返回值优化(NRVO - Named Return Value Optimization)。这意味着,即使从函数内部返回一个本地创建的
unique_ptr
class Product {
public:
Product(int id) : id_(id) { std::cout << "Product " << id_ << " constructed." << std::endl; }
~Product() { std::cout << "Product " << id_ << " destructed." << std::endl; }
void show_info() const { std::cout << "This is Product " << id_ << std::endl; }
private:
int id_;
};
// 工厂函数:创建一个 Product 对象并返回其所有权
std::unique_ptr<Product> create_product(int id) {
std::cout << "Inside create_product(" << id << ")" << std::endl;
// 这里创建一个本地的 unique_ptr
auto p = std::make_unique<Product>(id);
// 编译器会优化这里的返回,通常不会有移动操作
return p;
}
// 另一个函数,接收一个 unique_ptr,处理后返回一个新的 unique_ptr (或原始的)
std::unique_ptr<Product> transform_product(std::unique_ptr<Product> original_product, int new_id) {
std::cout << "Inside transform_product. Original product ID: ";
if (original_product) {
std::cout << original_product->id_ << std::endl;
// 假设我们在这里销毁旧的,创建一个新的
// 实际上也可以修改 original_product 并返回
} else {
std::cout << "null" << std::endl;
}
return std::make_unique<Product>(new_id); // 返回一个新的产品
}
int main() {
std::cout << "--- Creating product ---" << std::endl;
// 调用工厂函数,获取一个 Product 的所有权
std::unique_ptr<Product> my_product = create_product(1);
if (my_product) {
my_product->show_info();
}
std::cout << "\n--- Transforming product ---" << std::endl;
// 将 my_product 的所有权转移给 transform_product,并接收新的所有权
std::unique_ptr<Product> transformed_product = transform_product(std::move(my_product), 2);
// 此时 my_product 已经为空
if (transformed_product) {
transformed_product->show_info();
}
// transformed_product 在 main 结束时自动销毁
std::cout << "\n--- End of main ---" << std::endl;
return 0;
}为什么是最佳实践?
unique_ptr
unique_ptr
shared_ptr
unique_ptr
unique_ptr
避免返回原始指针(
T*
shared_ptr
unique_ptr
以上就是C++的std::unique_ptr作为函数参数或返回值时应该怎么传递的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号