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