是否有一种更习惯的方式来替换指针?

问题描述:

考虑下面的代码:是否有一种更习惯的方式来替换指针?

#include <memory> 
#include <stdio.h> 
#include <stdexcept> 

class Foo { 
    public: 
     Foo(int n) { val =n; printf("Hi %d\n", val); }; 
     ~Foo() { printf("Bye %d\n", val); }; 
    private: 
     int val; 
}; 

int main() 
{ 
    std::shared_ptr<Foo> p = nullptr; // I don't know what I want yet 
    p = std::make_shared<Foo>(1); // OK, I've decided 

    // I've changed my mind, it needs to be something else 
    p = nullptr; 
    p = std::make_shared<Foo>(2); 

    return 0; 
} 

它的输出是:

Hi 1 
Bye 1 
Hi 2 
Bye 2 

这是一个人为的例子。 Foo是一个相当无趣的。它只是打印出有关其寿命的信息。

代码背后的逻辑是:我声明p,但我不知道它应该是什么。然后我决定知道它是什么:它应该取值1.在我的真实代码中,这个值可能会持续很长时间。

一段时间后,我决定它不应该是1,它应该是2.因此,无论以前它应该被销毁,并被别的东西取代。

到目前为止,我的理解是上面的代码在内存管理方面很好,并且在异常情况下是健壮的。

有说的更地道的方式:我不能只写在最后一行,因为我想说的是,我收到需要被销毁

p = nullptr; 
p = std::make_shared<Foo>(2); 

+1

_“我不能只写最后一行,因为我想说我以前拥有的东西需要被销毁。”_什么让你只想到第二行除了分配'nullptr'之外,不会触发前一个值的销毁? –

+1

因为当我注释掉“p = nullptr”时,我得到输出Hi 1,Hi 2,Bye 1,Bye 2. IOW,第一个任务持续太久。 – blippy

+0

这是因为** 2 **对象是在赋值给'p'前创建的。如果你真的需要** 1 **对象在** 2 **创建之前被销毁,你需要在创建** 2 **之前将'p'设置为'nullptr'。没有成语,因为这是一个晦涩难懂的要求。 – Motti

仅分配给指针就足以告知您不需要以前的值。你不会说它是否应该被销毁,因为它是一个共享指针,并且可能有其他所有者。

在我看来,只分配就足够了,但您可能更愿意使用shared_ptr::reset()

+1

reset()效率较低,因为它会导致控制块和Foo实例分离。 –

+0

@RichardHodges,我同意,除非[它不是](https://lanzkron.wordpress.com/2012/04/22/make_shared-almost-a-silver-bullet/)。 – Motti

+0

但让我们现实。内存地点几乎总是比我们在一段时间内是否保留一些额外的内存更重要。复制一个shared_ptr或者锁定一个weak_ptr是一个常见的操作,并且*几乎总是*接着访问pointee对象本身。在这种情况下,在make_shared情况下,对象的开始(热部分)已经在数据缓存中等待您。 –

既然你要习惯(好!),让我们的是地道:

#include <memory> 
#include <stdexcept> 
#include <iostream> 

class Foo { 
public: 
    Foo(int n) 
    : val(n) 
    { 
     std::cout << "Hi " << val << "\n"; 
    }; 
    ~Foo() { 
     std::cout << "bye " << val << "\n"; 
    }; 
private: 
    int val; 
}; 

int main() 
{ 
    auto p = std::shared_ptr<Foo>(); // I don't know what I want yet 
    p = std::make_shared<Foo>(1); // OK, I've decided 

    // I've changed my mind, it needs to be something else 
    p = std::make_shared<Foo>(2); 

    return 0; 
} 

没有别的,你需要做

p = std::make_shared<Foo>(2); 

此行破坏之前的对象p如果是该对象的最后一个引用。然后它将新的shared_ptr分配给p值为新值