我已经阅读了有关初始化唯一指针的文档 这里.我尝试以相同的方式声明唯一指针(see unique_ptr<int> temp1 {&h}
,但我在文档中没有看到这种类型的声明,只是在实验(我声明了一个非智能指针。进行这个实验背后的想法是看看std::unique_ptr::get()
方法是如何工作的。这是代码:
#include<iostream>
#include<stdio.h>
#include<memory>
using namespace std ;
int main(){
int h {100};
unique_ptr<int> temp1 {&h};
cout<<"temp1.get() :"<<temp1.get()<<endl;
cout<< "&h : "<<&h<<endl;
cout<<"*temp : "<<*temp1<<endl;
return 0 ;
}
代码编译,我得到以下输出:
temp1.get() :0x7ffd4322c5cc
&h : 0x7ffd4322c5cc
*temp : 100
/home/abhishek/.codelite/tmp/abhishek/codelite-exec.sh: line 3: 7889 Segmentation fault (core dumped) ${command}
Hit any key to continue...
我可以看到std::unique_ptr::get()
返回托管对象的地址,与&h
相同。 这里的错误说什么? 尽管此处已讨论过为智能指针分配地址。它没有回答我的问题。
如下所述:
通过调用 get_deleter(((ptr( 使用可能由用户提供的删除程序来释放对象。默认删除程序使用 delete 运算符,该运算符销毁对象并解除分配内存。
unique_ptr
保存指向存储在堆上的动态分配变量的指针。初始化int h
时,将此变量存储在堆栈上。很明显,您不应该对未使用 new 动态分配的任何内容使用 delete,因此您必须这样做:
int* h_ptr = new int (100);
unique_ptr<int> temp1 {h_ptr};
如您链接的问题的答案之一中所述:
unique_ptr是指向对象的独占所有者。当它超出范围时,它将删除该对象。
也就是说,您传递给std::unique_ptr
的指针需要完全由生成的std::unique_ptr
拥有。这是因为一旦std::unique_ptr
有了指针,它就会管理指针,并在std::unique_ptr
超出范围时尝试delete
指针。
但是,这里的情况并非如此。h
是一个局部变量。一旦h
超出范围,它就会被摧毁。但一旦temp1
超出范围,它也会被摧毁。所以有两件事会试图摧毁它。这几乎肯定会导致未定义的行为,这可能是您在这里看到的。
这就是为什么您不应该将局部变量的地址传递给std::unique_ptr
,而是传递动态分配的地址,例如通过new
或std::make_unique()
。
为什么智能指针不能用通常的指针方式声明
std::shared_ptr
/std::uniqure_ptr
隐式持有对象的所有权,因此他们负责删除该对象,并且不允许您使用智能指针具有所有权delete
删除对象。std::experimental::observer_ptr
(TS v2( 和std::weak_ptr
不拥有所有权。
另一端的原始指针既可以拥有,也可以不拥有,因此您需要记录该指针是否拥有所有权,以及具有该指针的指针是否负责在其上调用delete
。
因此,您对unique_ptr<int> temp1 {&h};
执行的操作与您记录的原始指针相同,该原始指针是拥有原始指针,并且您在其上调用delete
。
int h {100};
int * temp1 = &h; // none owning pointer
// … some code here …
delete temp1; // calling delete on temp1 is not valid and would result in the same problem as with your unique_ptr example.
是否可以转让对象的所有权取决于存储持续时间
h
自动落入组中:
自动存储持续时间。对象的存储在封闭代码块的开头分配,并在末尾解除分配。所有本地对象都有此存储持续时间,但声明为静态、外部或thread_local的对象除外。
截至此,所有权无法转让,因为它完全由封闭代码块拥有。
只能转让具有动态存储持续时间的对象:
动态存储持续时间。通过使用动态内存分配函数为每个请求分配和取消分配对象的存储。有关使用此存储持续时间初始化对象的详细信息,请参阅 new-expression。
(自动通常称为在堆栈上分配,动态通常称为在堆上分配。