Reputation: 265
My first question here...
I want to use an abstract class A
from which i derive a class B
(and classes B2
, B3
, ...). I understood that in order to handle them uniformly, I have to use pointers to the base class, so here variables of type A*
.
In the example below, I want to fill aa
which is of type vector<A*>
in function f
. Since I can only use references and the variables lose their scope at the end of f
, I cannot access the members of the entries of aa
in main
anymore.
What could be a solution to this problem?
#include <vector>
#include <iostream>
class A {
public:
virtual int getVar(int, int) = 0;
};
class B : public A {
public:
B(std::vector<std::vector<int> > var) : var_(var) {};
int getVar(int i, int j) { return var_[i][j]; }
private:
std::vector<std::vector<int> > var_;
};
void f(std::vector<A*>& aa) {
std::vector<std::vector<int> > var(1, std::vector<int>(1));
var[0][0] = 42;
B b(var);
aa.push_back(&b);
}
int main() {
std::vector<A*> aa;
f(aa);
std::cout << aa[0]->getVar(0, 0) << std::endl;
return 0;
}
Upvotes: 3
Views: 6244
Reputation: 361352
B b(var);
aa.push_back(&b);
It is pushing the address of the local variable. That is the cause of the problem, because the local variable gets destroyed on returning from the functon, but aa
still contains the pointer to the non-existing object. Such a pointer is called dangling pointer using which invokes undefined behavior - which is one of the most dangerous and irritating aspect of C++.
Use new
:
aa.push_back(new B(var));
Now it should work.
Important : Don't forget to make ~A()
virtual:
class A {
public:
virtual ~A() {} //MUST DO IT
virtual int getVar(int, int) = 0;
};
It is necessary otherwise you wouldn't be able to delete objects of derived type (in a well-defined way), using the pointers of base type.
Upvotes: 7
Reputation: 299790
The problem you observe is a matter of scope.
There are two different allocation strategies in C++:
{ }
), its lifetime ends with the blocknew
(or new[]
if it's an array)If you want to create a variable and access it outside of its own scope, then you need to rely on dynamic storage. However, it's not free, because then you expose yourself to lifetime management issues, since it's now manual.
The recommendation is therefore to use the RAII idiom, to tie the lifetime of a dynamically allocated object to that of an automatically allocated one. In your case, using smart pointers (or containers).
Using C++11:
int main() {
std::vector< std::unique_ptr<A> > aa;
foo(aa);
std::cout << aa.front()->getVar(0,0) << "\n";
}
And updating foo
accordingly:
void foo(std::vector< std::unique_ptr<A> >& aa) {
std::vector<std::vector<int> > var(1, std::vector<int>(1));
var[0][0] = 42;
aa.push_back(new B(var));
}
Upvotes: 3
Reputation: 35039
The problem is within your f()
function. You are creating a automatically allocated object, that ceases to exist, once you exit the function. You have to allocat it on the heap, using new
.
B* b = new B(var);
aa.push_back(b);
Of course you have to free it on your own when you do not use it any more.
int main() {
...
for (std::vector<A*>::iterator it = aa.begin(); it != aa.end(); ++it)
{
delete *it;
}
return 0;
}
Upvotes: 2