1

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();   
}
JeJo
  • 30,635
  • 6
  • 49
  • 88
Chanoh Park
  • 254
  • 2
  • 16
  • 2
    What is wrong with simply using the shared pointer? Why the need for references? Returning references to local variables created inside functions is asking for trouble. – mathematician1975 Aug 06 '19 at 13:30
  • 1
    You might want to add the C++ tag here too to get more attention – mathematician1975 Aug 06 '19 at 13:33
  • Thanks for the comment! shared_ptr have a control block. I thought just returning shared_ptr will require extra cost to copy the control block. Is simply returning the shared pointer ok? – Chanoh Park Aug 06 '19 at 13:50
  • 1
    There will be only one instance of the object pointed to and that is created during your make_shared call. Returning a copy of the shared_ptr won't create another instance of the object the pointer points to. – mathematician1975 Aug 06 '19 at 14:03
  • 5
    In both cases, `func1` returns a dangling reference, referring to an object that has already been destroyed. Any attempt to actually use that reference would exhibit undefined behavior. It's not clear why you need `shared_ptr` here in the first place, but if you feel you do, just return it by value, the way `std::make_shared` does. – Igor Tandetnik Aug 06 '19 at 14:56

2 Answers2

2

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.

Caleth
  • 52,200
  • 2
  • 44
  • 75
1

I wanted to make a simple comment out of this, but there was too much to be said. This is meant to be a precision of mathematician1975's comment, which in my opinion is a good point to bring up.

I thought just returning shared_ptr will require extra cost to copy the control block.

You may want to have a look at (N)RVO/copy elision, which is precisely the mechanism avoiding this kind of thing: https://en.cppreference.com/w/cpp/language/copy_elision.

Long story short: returning it won't copy it, but instead will build it in-place at caller's site. No performance cost!

I've made a basic live example which shows how (N)RVO works, available here: http://coliru.stacked-crooked.com/a/8a32afc3775c685e


EDIT: If it can help clarifying the process of all this, I've written an article about copy elision and [N]RVO.

Razakhel
  • 732
  • 13
  • 34