13

NOTE: I've found the source of the error is not actually related to the shared_ptr, just cleverly disguised as such in the error message. Thus the below is basically nonsense (not the answers, they're fine)

--

I'm having some trouble using a shared_ptr (boost's at the moment) where I need to simply forward a pointer to another function. Using native pointers the intervening function would not need to have access to the definition of the class, but using smart_ptr's it appears it does. Is there any way to avoid this?

For example, given a target function:

void func( shared_ptr<SomeClass> const & obj )

The const & takes care of part of the problem, but say we have a getter class which obtains the object for some other class, like:

shared_ptr<SomeClass> someClassInstance();

And here is where I'd like to simply assemble arguments and forward to the target function:

func( someClassInstance() );

With a plain pointer this point in the code could simply use a forward declaration of SomeClass, but with a smart_ptr it needs to have the full definition (presumably as the smart_ptr might need to delete the class).

Now, if someClassInstance were to return a const & this problem would actually go away as the intervening code would not be copying any objects. However, the getter function must return the copy for thread-safety reasons.

Is there anyway I can achieve this type of smart pointer parameter forwarding without needing the class definition? That is, can I use smart pointers in the same fashion as I would a traditional pointer in this circumstance.

--

UPDATE: Writing a small test the answers are correct that a forward declaration is enough. Yet GCC is still complaining in one situation. I'm going to have to figure out exactly what is causing it to fail (in this particular situation).

Do I close this question for now, or what?

edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267
  • 3
    Why do you want to pass a `shared_ptr` by reference? Could a reference to the concrete type suffice? Also you have some sort of misconception, `shared_ptr` does not require the full definition of the type to be passed around, it works with incomplete types. – David Rodríguez - dribeas Jun 29 '11 at 15:43
  • you can't make `func` a template? – Nim Jun 29 '11 at 15:45
  • I'm just trying to pass by reference to avoid the problem (it helps in some cases). I guess I need to isolate the situation better in which it doesn't work. – edA-qa mort-ora-y Jun 29 '11 at 15:50
  • What makes you think you need the full definition? Are you getting an error message? – Alan Stokes Jun 29 '11 at 15:52
  • Could you post a minimal testcase for which gcc would complain? – Sebastian Mach Jun 29 '11 at 20:13
  • @phresnel, the unexpected source of the error is actually a typeid: see my other question http://stackoverflow.com/questions/6523878/obtaining-the-type-name-of-a-template-type-without-class-definition – edA-qa mort-ora-y Jun 30 '11 at 19:48

3 Answers3

18

You need at least a forward declaration for T for every mention of shared_ptr<T>.

Only if you use unary shared_ptr::operator* and shared_ptr::operator->, the full thing is needed. Under the hood, shared_ptr uses a mix of compiletime- and runtime-polymorphism, making this possible. See also this question to learn about the "magic".

Example:

// frob.h
#ifndef FROB_H
#define FROB_H

#include <shared_ptr>

class Foo;
void grind (std::shared_ptr<Foo>);

#endif

Note that the canonical way to pass shared_ptr is by value (i.e. remove the const&).

Community
  • 1
  • 1
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • Forward declaration is not enough. Since assigning by value might delete the underlying object you need to have the full definition. (This is the reason why I use const & to avoid this problem, but it doesn't always work). – edA-qa mort-ora-y Jun 29 '11 at 15:42
  • 2
    @edA-qamort-ora-y That’s not true. Assignment uses a custom deleter that is fixed by the constructor. Forward declaration is enough for the usage of `shared_ptr`; you only need the definition when calling its constructor. – Konrad Rudolph Jun 29 '11 at 15:45
  • 1
    under the hood `shared_ptr` uses a mix of runtime- and compiletime-polymorphism, which is why you actually don't need a full definition of the held type, provided you don't use `shared_ptr::operator->` and unary `shared_ptr::operator*`. Try it :) – Sebastian Mach Jun 29 '11 at 15:45
  • @edA-qa mort-ora-y: What do you mean by *assigning by value*? How does it affect? (Note that `shared_ptr` does not require a complete type for deletion, only for creation. – David Rodríguez - dribeas Jun 29 '11 at 15:46
  • @Konrad, that's what a colleague also said, now I'm trying to get GCC to agree with that statement. – edA-qa mort-ora-y Jun 29 '11 at 15:49
  • I'll just accept this answer, my question is bogus -- this answer is valid. – edA-qa mort-ora-y Jun 29 '11 at 16:18
3

Yes, shared pointers are specifically designed to work with incomplete types (a killer feature IMO). They require only a forward declaration of a class, not the class definition. From the Boost documentation:

Note that scoped_ptr requires that T be a complete type at destruction time, but shared_ptr does not.

You can find a discussion of how this works here.

Since shared pointers should work with incomplete types, can you give us a specific (minimal) example in which this doesn't work for you?

Martin B
  • 23,670
  • 6
  • 53
  • 72
0

It seems that explicit forward declaration is not always required:

using PtrX = std::shared_ptr<class X>;
using PtrW = std::weak_ptr<X>;

Here class X inside template argument does the magic.