Home > Blockchain >  Why did this assignment of a shared pointer have no effect after returning from nested function?
Why did this assignment of a shared pointer have no effect after returning from nested function?

Time:03-09

Consider this mwe:

#include<iostream>
#include<memory>
#include<vector>

using namespace std;

struct A {
    shared_ptr<vector<int>> b;
};

void foo(vector<A> &vec)
{
    auto c = shared_ptr<vector<int>>(new vector<int>{42});
    vec.back().b = c;
    cout << "Foo size " << vec.back().b->size() << endl;
}

void bar(A &a)
{
    auto vec = vector<A>{a};
    foo(vec);
}


int main()
{
    A a;
    bar(a);
    cout << "Main size" << a.b->size() << endl;
    return 0;
}

This is the program's output:

~ ./a.out                
Foo size 1
[1]    107400 segmentation fault (core dumped)  ./a.out

Why does a.b->size() yield in a segfault, instead of asking the vector which contains 42 to report its size?

Background: I have only very superficial knowledge of C . Usually I program in Python but recently (some weeks ago) I started working on someone else's C code base and added some features to it.

CodePudding user response:

std::vector and other standard containers always store copies of objects.

When you do auto vec = vector<A>{a};, a is copied into the vector, so any changes to the vector don't affect a.

CodePudding user response:

In main(), a.b doesn't point at a valid vector, so accessing a.b->size() is undefined behavior.

bar() creates a new vector that holds a copy of the A object that was passed in to it. foo() is then acting on that copied A object, not the original A object in main().

If you want foo() to act on the original A object in main(), you will have to change bar() to pass a vector<A*> instead to foo(), eg:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

struct A {
    shared_ptr<vector<int>> b;
};

void foo(vector<A*> &vec)
{
    auto c = shared_ptr<vector<int>>(new vector<int>{42});
    vec.back()->b = c;
    cout << "Foo size " << vec.back()->b->size() << endl;
}

void bar(A &a)
{
    auto vec = vector<A*>{&a};
    foo(vec);
}

int main()
{
    A a;
    bar(a);
    cout << "Main size" << a.b->size() << endl;
    return 0;
}
  • Related