Let's say i have the following structs:
struct Foo
{
int val;
};
struct Test
{
Foo *bar;
};
and I wanted to create a Test
struct:
Test get_test()
{
Test test;
Foo foo;
foo.val = 10;
test.bar = &foo;
cout << "INIT: " << test.bar->val << endl;
return test;
}
int main()
{
Test test = get_test();
cout << "AFTER: " << test.bar->val << endl;
return 0;
}
The output is the following:
INIT: 10
AFTER: 32723
I tried to do this differently:
Test get_test()
{
Test test;
Foo *foo;
foo->val = 10;
test.bar = foo;
cout << "INIT: " << test.bar->val << endl;
return test;
}
But this gave me a SIGSEGV (Address boundary error)
From my limited understanding, I believe it is because in get_test()
foo
is a temporary variable, so the reference doesn't mean anything. How can I do this properly?
You are on the right track. In your first example, once get_test
returns, foo
does not exist anymore, and accessing the address where it was is undefined behavior. The same happens in your second try, but here the problem is in get_test
itself. You declare Foo* foo;
, but never assign it to anything, which means that the variable foo
is pointing to some random address. Accessing it is undefined behavior.
Try this as your get_test
-function:
Test get_test()
{
Test test;
Foo *foo = new Foo();
foo->val = 10;
test.bar = foo;
cout << "INIT: " << test.bar->val << endl;
return test;
}
Here, we allocate foo
with new
, so it is allocated on the heap, and will remain until you call delete
on it. This means you need to make sure to delete
it once you are done with it or you will have a memory-leak. In c++14, you could also do it using std::unique_ptr
:
struct Test
{
std::unique_ptr<Foo> bar;
};
{
Test test;
std::unique_ptr<Foo> foo = std::make_unique<Foo>();
foo->val = 10;
test.bar = std::move(foo);
cout << "INIT: " << test.bar->val << endl;
return test;
}
std::unique_ptr
will take care of deleting foo
once it goes out of scope (when test
is destroyed), and you don't have to worry about memory-leaks (but you cannot copy a std::unique_ptr
, so you will have to std::move
it).
std::unique_ptr
is available since c++11, std::make_unique
since c++14.
You will also need to #include <memory>
to be able to use them.
Check out this link to learn more about the difference between heap and stack, and this one to learn more about std::unique_ptr
and move-semantics.