C++ 独特的_ptr<;T>;。使用原始指针赋值时get()方法调用析构函数?

C++ 独特的_ptr<;T>;。使用原始指针赋值时get()方法调用析构函数?,c++,pointers,c++11,crash,unique-ptr,C++,Pointers,C++11,Crash,Unique Ptr,下面的程序使用std::unique_ptr来避免手动内存管理。我尝试了两种方法来实现它。问题在于第二种方法,在分配给原始指针之前,调用析构函数。当以后的代码试图访问无效内存时,这会导致程序崩溃 我在第二种方法中的意图是,如何使用具有现有代码库的智能指针,以便我可以利用智能指针提供的自动内存管理。因此,我没有更改声明中指针的类型(.e.从Widget*w到std::unique_ptr w) 有人能详细解释一下吗?最好的做法是什么?。或者我错过了什么 #include<iostream&g

下面的程序使用
std::unique_ptr
来避免手动内存管理。我尝试了两种方法来实现它。问题在于第二种方法,在分配给原始指针之前,调用析构函数。当以后的代码试图访问无效内存时,这会导致程序崩溃

我在第二种方法中的意图是,如何使用具有现有代码库的智能指针,以便我可以利用智能指针提供的自动内存管理。因此,我没有更改声明中指针的类型(.e.从
Widget*w
std::unique_ptr w

有人能详细解释一下吗?最好的做法是什么?。或者我错过了什么

#include<iostream>
#include<memory>
class Widget {
public:
    Widget() { std::cout << "Widget::Widget()" << std::endl; }
    virtual ~Widget() { std::cout << "Widget::~Widget()" << std::endl; }
    virtual void draw() = 0;
};

class WindowsButton : public Widget {
public:
    WindowsButton() = default;
    ~WindowsButton() = default;
    void draw() { std::cout << "WindowsButton"<<std::endl; }
};

int main() {    
    // Working Code
    // std::unique_ptr<Widget> w = std::unique_ptr<Widget>(new WindowsButton());
    // w.get()->draw();

    //In this way program is crashing while calling the w->draw()
    Widget* w = std::unique_ptr<Widget>(new WindowsButton()).get();
    w->draw();
}
#包括
#包括
类小部件{
公众:

Widget(){std::cout在第二种情况下,您正在创建一个
unique\u ptr
的临时实例,并在其上调用
get()
成员函数。
unique\u ptr
对象将在完整表达式的末尾(分号处)被销毁


然后将取消引用指向无效内存位置的指针,从而导致未定义的行为。

在第二种情况下,您正在创建一个
unique\u ptr
的临时实例,并对其调用
get()
成员函数。
unique\u ptr
对象将在完整表达式结束时销毁(在分号处)

然后将取消引用指向无效内存位置的指针,从而导致未定义的行为。

在这一行中

Widget* w = std::unique_ptr<Widget>(new WindowsButton()).get();
当时,
w
是一个悬空的指针。

在这行中

Widget* w = std::unique_ptr<Widget>(new WindowsButton()).get();

那时,
w
是一个悬而未决的指针。

也许你误解了一点
unique\u ptr
。它不是帮助管理原始指针的内存,而是替换原始指针。在这两个示例中,你都返回到调用
get()
unique\u ptr
上获取原始指针并使用它。这是不需要的。您可以使用
unique\u ptr
完成所有使用原始指针的操作,除了复制它并调用
delete

您在第二个示例中遇到的问题是生存期问题。由于
unique\u ptr
拥有它指向的对象,因此它控制其生存期,这意味着当
unique\u ptr
被销毁时,该对象必须被销毁。由于
unique\u ptr
是一个临时对象,因此它会在同一行中销毁该对象

因此,临时的
unique\u ptr
s几乎没有什么用处,除非您使用它们初始化另一个
unique\u ptr
共享的\u ptr
或其他接管所有权的对象,从而使
unique\u ptr
为空

在以下几行中,我将稍微润色一下您的“工作代码”:

这是C++03风格的使用方法,C++11也可以。人们对如何以及何时使用C++11功能(如
auto
和统一初始化)给出了不同的建议,因此下面是一些在C++11中也会很好/更好的示例:

std::unique_ptr<Widget> w{new WindowsButton{}};

在这里,
w
有类型
std::unique\u ptr
,但这通常不会有什么影响,因为如果需要,它可以转换为
std::unique\u ptr

可能您误解了一点
unique\u ptr
。这不是帮助原始指针的内存管理的方法,而是替换原始指针。在两个示例中返回到对
unique\u ptr
调用
get()
,以获取原始指针并使用它。这不是必需的。您可以使用
unique\u ptr
执行原始指针的所有操作,除了复制和调用
delete

您在第二个示例中遇到的问题是生存期问题。由于
unique\u ptr
拥有它指向的对象,因此它控制其生存期,这意味着当
unique\u ptr
被销毁时,该对象必须被销毁。由于
unique\u ptr
是一个临时对象,因此它会在同一行中销毁该对象

因此,临时的
unique\u ptr
s几乎没有什么用处,除非您使用它们初始化另一个
unique\u ptr
共享的\u ptr
或其他接管所有权的对象,从而使
unique\u ptr
为空

在以下几行中,我将稍微润色一下您的“工作代码”:

这是C++03风格的使用方法,C++11也可以。人们对如何以及何时使用C++11功能(如
auto
和统一初始化)给出了不同的建议,因此下面是一些在C++11中也会很好/更好的示例:

std::unique_ptr<Widget> w{new WindowsButton{}};

在这里,
w
有类型
std::unique_ptr
,但这通常不会有什么伤害,因为如果需要,它可以转换为
std::unique_ptr

简单地制作
w
a
std::unique_ptr
,有什么问题吗?@0x499602D2:更改原型没有问题。但正如我在文章中提到的那样,所以我想要在第一种情况下,
unique_ptr
提供了一个
操作符->()
重载,因此
w->draw();
可以工作。您必须构造一个
std::unique_ptr
然后调用
get())
简单地制作
w
a
std::unique_ptr
有什么问题?@0x499602D2:更改原型没有问题。但是正如我在中提到的,我想在现有的代码库中做这件事。不需要
w.get()->draw()
在第一种情况下,
unique\u ptr
提供了一个
操作符->()
重载,因此
w->draw();
可以工作。您必须构造一个
std::unique\u ptr
然后调用
get()
std::unique_ptr<Widget> w = std::unique_ptr<Widget>(new WindowsButton());
w.get()->draw();
std::unique_ptr<Widget> w(new WindowsButton());
w->draw();
std::unique_ptr<Widget> w{new WindowsButton{}};
auto w{std::unique_ptr<Widget>{new WindowsButton{}}};
auto w{std::make_unique<WindowsButton>()};