vector of pointers crashes

The first example crashed, the last two examples work fine.

The first example has vector of pointer to a derived object.
Why does it crash?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <vector>
using namespace std;

class A
{
    public:
	virtual void funcA()=0;
};
class A1: public A
{
    public:
	void funcA() { cout << " A1"; };
};
class A2: public A
{
    public:
	void funcA() { cout << " A2"; };
};

int main()
{
	vector<A1*> a1 (1);
	a1.push_back(new A1);
	(a1[0])->funcA(); // crashed
}


The second example has the same main() as the first example, but there is no polymorphism.
This does not crash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <vector>
using namespace std;

class A1
{
    public:
	void funcA() { cout << " A1"; };
};

int main()
{
	vector<A1*> a1 (1);
	a1.push_back(new A1);
	(a1[0])->funcA(); // no crash
}


The third example has the same polymorphism as first example, but there is no vector.
This does not crash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <vector>
using namespace std;

class A
{
    public:
	virtual void funcA()=0;
};
class A1: public A
{
    public:
	void funcA() { cout << " A1"; };
};
class A2: public A
{
    public:
	void funcA() { cout << " A2"; };
};

int main()
{
	A1 *a1 = new A1;
	a1->funcA(); // no crash
}

Thank you.
Example 1:
Constructing a vector of size 1, then adding an A1 to the end of the vector probably isn't what you expected.
1
2
3
4
5
6
7
8
	vector<A1*> a1 (1); // create vector with one pointer
        // v = {invalid pointer} (size 1)

	a1.push_back(new A1); // add another pointer
        // a1 = {invalid pointer, A1*} (size 2)

	(a1[0])->funcA(); // crashed
        // (invalid pointer)->funcA() 


Instead, either create an empty vector then push back (which is preferred way). Or create vector of size 1 and explicitly set v[0] = new A1

Last edited on
Thank you nkendra! That worked:
1
2
3
	vector<A1*> a1;
	a1.push_back(new A1);
	(a1[0])->funcA();
I think I know the reason why the non virtual example didn't crash. The funcA() function does not use any state inside the A1 class. For the non virtual example, the program is just calling a function without really needing a valid A1 pointer. In the polymorphic example, A1 actually contains some "invisible" data (vpointer) that identifies the type of A1, because A1 inherits from A.

The program tries to access that vpointer and realizes the pointer is invalid. Now, I wonder why this happens because A1::funcA() is not declared as virtual and the function call inside main is using an A1 pointer, not the parent A pointer. So the compiler knows it needs to call A1::funcA() in example 2. I wonder why the compiler is not calling the funcA() the same way as in the non virtual example. Maybe someone else can explain this.

But in any case, never call a function on an invalid pointer.
> The funcA() function does not use any state inside the A1 class.
> For the non virtual example, the program is just calling a function without really needing a valid A1 pointer.
> In the polymorphic example, A1 actually contains some "invisible" data (vpointer)

nkendra +1



> I wonder why the compiler is not calling the funcA() the same way as in the non virtual example.

There is a quality of implementation issue involved. The pointer obtained is from the innards of a vector; most compilers wouldn't do the huge amount of static analysis required to determine that the buffer held by the vector is not aliased, and therefore a1[0] must always be a pointer to an object with A as its dynamic type.

In a simpler situation, with no vector (and allocator) involved, the compiler would typically be able to elide the run-time vtbl lookup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*  g++ -std=c++11 -Wall -Wextra -pedantic-errors -O3 -fomit-frame-pointer -c -S test.cc */
/* .ident	"GCC: (GNU) 4.9.0 20131020 (experimental)" */

struct A
{
    virtual ~A() {}
    virtual int value() const { return 7 ; }
};

int foo()
{
    A a ;
    A& ra = a ;
    return a.value() ; // inlined; resolved at compile time to A::value()
    /*
    __Z3foov:
        movl	$7, %eax
        ret
    */
}

int bar()
{
    A a ; // local object, not aliased
    A* pa = &a ; // it is known at compile time that pa always points to 'a'
    return pa->value() ; // inlined; resolved at compile time to A::value()
    /*
    __Z3barv:
        movl	$7, %eax
        ret
    */
}

int baz()
{
    A* pa = new A ; // it is known at compile time that pa always points to 'a'

    return pa->value() ; // inlined; resolved at compile time to A::value()
    /*
	subl	$28, %esp
	movl	$4, (%esp)
	call	__Znwj ; call ::operator new
	movl	$__ZTV1A+8, (%eax)
	movl	$7, %eax ; inlined
	addl	$28, %esp
	ret
	*/
}


Thanks for the explanation JLBorges. My thinking was that, since A1::funcA() is not declared virtual, one (and only one) function can be called by vector<A1*>[i]->funcA().

1
2
3
4
5
6
7
8
9
vector<A1*> v;
v.push_back((A1*)new A2);
v[0]->funcA(); // I would think this could only call A1::funcA()


// or how about
v.push_back((A1*)&someWeirdType);
v[1]->funcA();
Last edited on
> My thinking was that, since A1::funcA() is not declared virtual,
> one (and only one) function can be called by vector<A1*>[i]->funcA().

Yes. The issue of compile-time determination of the dynamic type of the object pointed to (to optimize away the cost of run-time look up) arises only if the function is virtual. If it is not virtual, one (and only one) function can be called.



1
2
3
> // or how about
> v.push_back((A1*)&someWeirdType);
> v[1]->funcA();


Depends on what someWeirdType is.
If it is an unrelated type, the cast is a reinterpret_cast and the result is undefined behaviour.
Topic archived. No new replies allowed.