Search code examples
c++c++11pass-by-referencesmart-pointers

What are the pros and cons of receiving a variable as a reference with std::shared_ptr?


I just wondering if the following way of delivering a pointer variable, created inside of the func1, to the caller (func2) is a correct way of doing this. If this is correct, will it release the memory when func2 is returned? If it is a bad idea, why is that?

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


void func2(){

    int & dd = func1();   

}

This is a simplified code. I am assuming the size of d is huge(e.g images).

Added: I realized that the following also works. What will be the pros and cons of each approach?

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();   
}

Solution

  • Both of those examples are bad. You can't use the return values of either func1, they are always dangling references.

    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
    

    I am assuming the size of d is huge

    You are mistaken. The size of the object pointed-to by d has no bearing on the size of d, just like with raw pointers.

    E.g.

    #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 results in

    4
    8
    16
    8
    400000
    8
    16
    8
    

    I realized that the following also works

    If by works, you mean "is accepted by a C++ compiler", then yes. They both result in undefined behaviour if you use the references returned, so I would say they categorically don't work.