Reputation: 420
I would like to store multiple classes with the same base class in a std::vector
. After some research, it became apparent to me that I have to use pointers to prevent object slicing. However, when I create the vector, add elements to it and return it, the resulting vector doesn't have the right values.
As an example, here are my two classes:
class Base {
public:
int var0;
}
class Derived : public Base {
public:
int var1;
}
And here is a simple print
function. As a rule, all instances of Base
should have var0 == 23
, and all instances of Derived
should have var0 != 23
.
void print(Base& value) {
if (value.var0 == 23) {
std::cout << "Base: " << value.var0 << std::endl;
} else {
Derived d = (Derived&) value;
std::cout << "Derived: " << d.var0 << ", " d.var1 << std::endl;
}
}
First of all, this does work like I want it to:
int main() {
int num = 10;
std::vector<Base*> vec;
for (int i = 0; i < num; i++) {
if (i % 2 == 0) {
Base b;
b.var0 = 23;
vec.push_back(&b);
} else {
Derived d;
d.var0 = 17;
d.var1 = 42;
vec.push_back(&d);
}
}
// ....
for (int i = 0; i < num; i++) {
print(*vec.at(i));
}
}
This prints:
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Now, I want this vector to be returned by a function, so I create a function:
std::vector<Base*> createVector(int num) {
std::vector<Base*> vec;
for (int i = 0; i < num; i++) {
if (i % 2 == 0) {
Base b;
b.var0 = 23;
vec.push_back(&b);
} else {
Derived d;
d.var0 = 17;
d.var1 = 42;
vec.push_back(&d);
}
}
return vec;
}
int main() {
int num = 10;
std::vector<Base*> vec = createVector(num);
// ....
for (int i = 0; i < num; i++) {
print(*vec.at(i));
}
}
This prints:
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Which is not what I want. I want it to print like the other function did.
Is there any way to solve this problem? Any way to maybe do the whole derived-class thing a bit better?
Upvotes: 3
Views: 3168
Reputation: 409166
This has nothing to do with object slicing, and everything to do with you storing pointers to local variables in the vector. Once the scope the variables were declared in has ended, the variables are destructed leaving you with stray pointers, and dereferencing these stray pointers leads to undefined behavior.
You have this problem also in the program that you says work fine. Seemingly working fine is one or the possibilities of undefined behavior.
Upvotes: 3
Reputation: 234665
Your program behaviour is undefined:
Base b;
b.var0 = 23;
vec.push_back(&b);
is pushing back a pointer to a variable (b
) that goes out of scope.
Why not use a std::vector<std::unique_ptr<Base>>
instead? Object slicing will not be an issue, and the vector will manage the memory for you.
Upvotes: 8