【问题标题】:What are the pros and cons of receiving a variable as a reference with std::shared_ptr?使用 std::shared_ptr 接收变量作为参考的优缺点是什么?
【发布时间】:2019-12-13 17:39:12
【问题描述】:

我只是想知道以下将在func1 内部创建的指针变量传递给调用者(func2)的方法是否是正确的方法。如果正确,返回func2时会释放内存吗?如果这是一个坏主意,为什么会这样?

int & func1()
{
  std::shared_ptr<int> d = std::make_shared<int>(50);
  return *d;
}


void func2(){

    int & dd = func1();   

}

这是一个简化的代码。我假设d 的大小很大(例如图片)。

添加: 我意识到以下也有效。每种方法的优点缺点是什么?

std::shared_ptr<int> & func1()
{
  std::shared_ptr<int> d = std::make_shared<int>(50);
  return d;
}

void func2()
{  
    std::shared_ptr<int> & dd = func1();   
}

【问题讨论】:

  • 简单地使用共享指针有什么问题?为什么需要参考?返回对在函数内部创建的局部变量的引用是自找麻烦。
  • 您可能还想在此处添加 C++ 标签以获得更多关注
  • 感谢您的评论! shared_ptr 有一个控制块。我认为仅返回 shared_ptr 将需要额外的成本来复制控制块。简单地返回共享指针好吗?
  • 只有一个指向对象的实例,它是在您的 make_shared 调用期间创建的。返回 shared_ptr 的副本不会创建指针指向的对象的另一个实例。
  • 在这两种情况下,func1 返回一个悬空引用,指向一个已经被销毁的对象。任何实际使用该引用的尝试都会表现出未定义的行为。不清楚为什么首先需要shared_ptr,但如果你觉得需要,只需按值返回,就像std::make_shared 一样。

标签: c++ c++11 pass-by-reference smart-pointers


【解决方案1】:

我想对此做一个简单的评论,但要说的太多了。这是数学家 1975 评论的精确性,我认为这是一个很好的观点。

我认为仅仅返回 shared_ptr 将需要额外的成本来复制控制块。

您可能想看看 (N)RVO/copy elision,这正是避免这种事情的机制:https://en.cppreference.com/w/cpp/language/copy_elision

长话短说:返回它不会复制它,而是会在调用者的站点就地构建它。没有性能成本!

我制作了一个基本的实时示例,展示了 (N)RVO 的工作原理,可在此处获取:http://coliru.stacked-crooked.com/a/8a32afc3775c685e


编辑:如果它可以帮助澄清这一切的过程,I've written an article 关于复制省略和 [N]RVO。

【讨论】:

    【解决方案2】:

    这两个例子都很糟糕。你不能使用func1 的返回值,它们总是悬空引用。

    int & func1()
    {
      std::shared_ptr<int> d = std::make_shared<int>(50);
      return *d;
    } // d is the only owner when it is destroyed, *d is also deleted
    
    std::shared_ptr<int> & func1()
    {
      std::shared_ptr<int> d = std::make_shared<int>(50);
      return d;
    } // d is destroyed here
    

    我假设d 的大小很大

    你错了。 d指向的对象的大小与d 的大小无关,就像原始指针一样。

    例如

    #include <iostream>
    #include <memory>
    
    struct Huge
    {
        int data[100000];
    };
    
    int main()
    {
        std::cout << sizeof(int) << std::endl 
            << sizeof(int*) << std::endl 
            << sizeof(std::shared_ptr<int>) << std::endl 
            << sizeof(std::unique_ptr<int>) << std::endl
            << sizeof(Huge) << std::endl 
            << sizeof(Huge*) << std::endl 
            << sizeof(std::shared_ptr<Huge>) << std::endl 
            << sizeof(std::unique_ptr<Huge>) << std::endl;
    }
    

    for me 结果

    4
    8
    16
    8
    400000
    8
    16
    8
    

    我意识到以下也有效

    如果按工程,您的意思是“被 C++ 编译器接受”,那么是的。如果您使用返回的引用,它们都会导致未定义的行为,所以我会说它们绝对不起作用

    【讨论】:

      猜你喜欢
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 2019-11-14
      • 1970-01-01
      • 2021-12-18
      • 2016-04-10
      • 1970-01-01
      • 2011-08-20
      相关资源
      最近更新 更多