3

I'm working with a codebase where I can't solve this circular dependency:

foo.h

class Foo
{
public:
  using Ptr = std::shared_ptr<Foo>;
  using ConstPtr = std::shared_ptr<const Foo>;

  void setter(const Bar::Ptr& bar_ptr) {};

private:
  Bar::WeakPtr bar_ptr_;
};

and

bar.h

class Bar
{
public:
  using Ptr = std::shared_ptr<Bar>;
  using ConstPtr = std::shared_ptr<const Bar>;
  using WeakPtr = std::weak_ptr<Bar>;

  Bar(Foo::ConstPtr foo_ptr) : foo_ptr_(std::move(foo_ptr)) {};

private:
  Foo::ConstPtr foo_ptr_;
};

It was previously compiling because there was an external header where:

using FooPtr = std::shared_ptr<Foo>;
using FooConstPtr = std::shared_ptr<const Foo>;
using BarPtr = std::shared_ptr<Bar>;

But since consistency is sought after, I'd like to have Foo::Ptr, Foo::ConstPtr, Bar::Ptr. Any chance I can get it?

Coliru

EDIT: added the Bar::WeakPtr which was previously missing since I thought I was already in trouble.

5
  • Can you explain the requirement of using and not using a variable? Commented Mar 15, 2020 at 23:32
  • @cigien: No, these aren't nested Commented Mar 15, 2020 at 23:48
  • 1
    @jackw11111 using is to hide the fact that it's a std::shared_ptr instead of a boost::shared_ptr sometimes soon. It's actually using Ptr = my_namespace::shared_ptr<Foo>; Commented Mar 16, 2020 at 0:11
  • 1
    Foo doesn't have a Bar::Ptr member that setter() assigns to, in fact setter() doesn't participate in shared ownership of Bar at all, so it shouldn't be taking a shared_ptr<Bar> at all (herbsutter.com/2013/06/05/…), thus you could break the circular dependency by changing Foo::setter() to void setter(const Bar* bar_ptr) and then forward-declare Bar Commented Mar 16, 2020 at 0:52
  • @RemyLebeau You're almost right, I just checked and Foo has a Bar::WeakPtr. I simplified too much the example, let me fix it. Commented Mar 16, 2020 at 8:39

2 Answers 2

2

This is arguably a deficiency of C++. You cannot declare just some public names of a class without including the whole class definition. In this setting, I am afraid your circular dependency cannot be resolved - at least not in a way that won't bite you in some way in the future.

However, as an alternative, consider using a template definitions outside of the subject class. It changes the order of terms, but not the overall meaning:

template<class T>
struct PtrStruct {
    using type = std::shared_ptr<T>;
};

template<class T>
using Ptr = typename PtrStruct<T>::type;

template<class T>
struct ConstPtrStruct {
    using type = std::shared_ptr<const T>;
};

template<class T>
using ConstPtr = typename PtrStruct<const T>::type;

In this setting your Foo::Ptr becomes Ptr<Foo> and Foo::ConstPtr becomes ConstPtr<Foo>. You still can:

  • at a later stage replace std::shared_ptr with something different at a single place where PtrStruct is defined. Rest of the code will compile without a change, as long as the used interface didn't change.
  • specialize PtrStruct for specific T if it should be something different than the rest.
Sign up to request clarification or add additional context in comments.

Comments

0

If consistency is sought after, do not create ill-formed structures. You can try something like:


// Foo.h

class Bar;

class Foo
{
public:
  using BarPtr = std::shared_ptr<Bar>;

  void setter( BarPtr bar_ptr)
  {}
};


// Bar.h

class Foo;

class Bar
{
public:
  using ConstFooPtr=std::shared_ptr<const Foo>;

  Bar( ConstFooPtr foo_ptr)
      : foo_ptr_( std::move( foo_ptr))
  {}

private:
  ConstFooPtr foo_ptr_;
};

3 Comments

You got the Ptr and ConstPtr in the classes swapped
In original post there seems to be a discrepancy in bar.h: the constructor takes a shared_pointer to const Foo object and tries to store in shared_ptr to non-const Foo object.
@Andreas_75 fixed

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.