Trying to pass an abstract class reference to shared_ptr?

Hi guys,

So I'm trying to kinda do a Java thing with C++ which is apparently capable. I'm trying to pass a reference of a base abstract class to a different class and then make it a shared_ptr, like this:

SimpleApplication.cpp:
mp_stateManager = std::make_shared<managers::AppStateManager>(*this);

AppStateManager.cpp:
AppStateManager(gyroInterface::GyroApplication& app) :
mp_app(std::make_shared<gyroInterface::GyroApplication>(app) {
//...
}

GyroApplication is a pure abstract class.

When I run this code in Netbeans I get the following error:

"note: in instantiation of function template specialization"

But when I do this:

AppStateManager(gyroInterface::GyroApplication& app) {
gyroInterface::GyroApplication* diffApp = &app;
}

It works... Am I missing something? Or am I making a stupid mistake that new people tend to make?

Cheers Guys!

Jamie.
Is mp_app a shared_ptr?
Note that make_shared is used to create new objects. In the AppStateManager constructor it's trying to create a new GyroApplication object but that is not possible because GyroApplication is an abstract class.

It is possible to use the shared_ptr constructor to construct a shared_ptr for an already existing object but then that object should have been created with new (unless you specify a custom deleter) and there should exist no other shared_ptrs pointing to the same object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Creates a shared_ptr to a local variable.
// This is incorrect because the shared_ptr will try to use delete
// when it goes out of scope but delete should never be used on 
// local variables, only on objects that has been created with new.
{
	int i = 5;
	std::shared_ptr<int> sp(&i);
}

// Creates a shared_ptr to a dynamically allocated object.
// This could work but you need make sure not to use the raw poiner
// ip after the shared_ptr has deleted it.
{
	int* ip = new int(5);
	std::shared_ptr<int> sp(ip);
}

// By using make_shared you can combine the creation of the object and 
// shared_ptr into one step. This is less error prone because you get 
// rid of additional access paths that might become invalid.
{
	auto sp = std::make_shared<int>(5);
}

It is off course possible to have multiple shared_ptrs pointing to the same object but then that should be done by first creating a shared_ptr to the object (preferably using make_shared) and then create copies of it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Two independent shared_ptrs pointing to the same object. This is not 
// correct. The two shared_ptrs are keeping their own independent 
// reference counter so when one of them is destroyed the object gets 
// deleted while it's still being used by the other shared_ptr. At the
// very least it would lead to the object beeing deleted twice.
{
	int* ip = new int(5);
	std::shared_ptr<int> sp1(ip);
	std::shared_ptr<int> sp2(ip);
}

// This has the same problem as above.
{
	auto sp1 = std::make_shared<int>(5);
	std::shared_ptr<int> sp2(&*sp1);
}

// This is the correct way of doing it. The two shared_ptrs are sharing 
// reference counter and the object will not be deleted until all of the
// shared_ptrs are gone.
{
	auto sp1 = std::make_shared<int>(5);
	auto sp2 = sp1;
}

Even if you store the object as a shared_ptr you can still pass the object by reference to functions that use it. Functions that receive an object by reference should not try to take ownership by constructing a shared_ptr to the object because it doesn't know if it's safe to do so.

1
2
3
4
void foo(int&);

auto sp = std::make_shared<int>(5);
foo(*sp);

A function that should be allowed to take ownership should instead take the shared_ptr as argument, and then it can safely create a copy of the shared_ptr if it wish.

1
2
3
4
void bar(const std::shared_ptr<int>&);

auto sp = std::make_shared<int>(5);
bar(sp);

Smart pointers is all about ownership. Who is owning the object? If there is only one owner you can use std::unique_ptr. If you want to support multiple owners you can use std::shared_ptr. The object gets destroyed when there are no owners left.

Smart pointers are best suited for strict hierarchies (i.e. no object is owned, directly or indirectly, by other objects that it owns). Circular ownership (A owns B and B owns A) is not obvious how to handle. You can't simply allow them both to have smart pointers to each other because then they would never get destroyed, unless you have some way of manually breaking the connection but then you lose much of the benefit of using smart pointers in the first place. If you can't think of a way to break the circular ownership there is a class template called std::weak_ptr that might be useful.
Last edited on
Topic archived. No new replies allowed.