Is there a way to define circular references without using pointers?
I need to have somthing like this:
struct A;
struct B {
A a;
};
struct A {
B b;
};
Thanks!
You can use references instead
struct A;
struct B {
A& a;
};
struct A {
B b;
};
But no it's not possible to create a circular reference without some level of indirection. What your sample is doing is not even creating a circular reference, it's attempting to create a recursive definition. The result would be a structure of infinite size and hence not legal.
No, there's not. Such structure would have infinite size.
You can use smart pointers (shared_ptr and weak_ptr) to avoid direct pointer manipulation, but that's about it.
How could this work? If I remember correctly, the address value of a reference can't be modified once set, so you can't define a circular reference.
It could work like the following (same as Jared's example plus constructors defined):
struct A;
struct B {
A& m_a;
B(A& a) : m_a(a) {}
};
struct A {
B m_b;
//construct B m_b member using a reference to self
A() : m_b(*this) {}
//construct B m_b member using a reference to other
A(A& other) : m_b(other) {}
};
In C++, T o means "an object of type T, not a reference to some T (as, for example, with reference types in C# and Java). With the code from your question, type A would have a sub object of type B (named b), and that B in turn would have a sub object of type A (named a). Now, that a would in turn have another A inside (again called a), which then has another B, which...
No, this will not work.
What you probably want is that an A referres to a B, which in turn referres that A. This can be done using pointers:
struct A;
struct B {
A* a;
B(A*);
};
struct A {
B* b;
A(B* b_) : b(b_) { if(b) b.a = this; }
};
B::B(A* a_) : : a(a_) { if(a) a.b = this; }
I don't think it can be done using references.
ChrisW's solution can be generalized a bit like this :
template <class defaultState> struct Context;
struct State1 {
Context<State1>& mContext;
State1(Context<State1> & ref) : mContext(ref) {}
};
template <class TDefaultState>
struct Context {
TDefaultState mState;
Context() : mState(*this) {}
};
This now allows you to do
Context<State1> demo;
Further, State can have some template helper code as well
template <class State>
struct TState {
typedef Context<State> TContext;
typedef TState<State> TBase;
Context<State> & mContext;
TState(Context<State> &ref) : mContext(ref) {}
};
struct State2 : TState<State2> {
State2(TContext & ref) : TBase(ref) {}
};
struct State3 : TState<State3> {
State3(TContext & ref) : TBase(ref) {}
};
Which now allows you to do any of
Context<State2> demo2;
Context<State3> demo3;
Related
I have a class A that provides methods to construct instances of class B. And B holds a private reference to A and provides a constructor to set this reference.
class A {
public:
B* construct_B ();
}
class B {
private:
const A& private_A;
public:
B ( const A& my_A ): private_A (my_A) { }
}
The implementation of construct_B takes care of dynamic allocation and passing the reference to itself via this.
How do I implement this setup in such a way that I make sure that the lifetime of A is longer than B so that its reference remains valid? Notice that I don't care about all the possibilities of construct_B instead of returning a raw pointer I could return a smart pointer or similar.
One possible way of solving this could be having B instead of holding a reference to hold a smart pointer to A, and instead of dynamically allocating B in construct_B to take a static reference to B and then set it's pointer, something like
class A :
public std::enable_shared_from_this<A> {
public:
void setup_B ( const B& my_B ) {
my_B.set_A (shared_ptr_from_this() ) ;
}
class B {
private:
const shared_ptr<A> private_A_ptr;
public:
void set_A ( const shared_ptr<A> my_A ):
private_A_ptr (my_A) { }
}
which then could be implemented by
int main () {
A static_A;
B static_B;
A.setup_B (static_B);
}
Does the shared_ptr of this last construction avoid the problem of A being deleted before B?
shared_ptr is your answer. Something like this:
#include <memory>
struct A;
class B {
const std::shared_ptr<A> private_A_ptr;
public:
B(std::shared_ptr<A> parent) : private_A_ptr(std::move(parent)) {}
};
struct A :
std::enable_shared_from_this<A>
{
B make_b() {
return B(shared_from_this());
}
};
int main()
{
// this would be invalid:
//A a;
//auto b = a.make_b();
// but this is fine
auto pa = std::make_shared<A>();
auto b = pa->make_b();
// later...
pa.reset();
// A still exists because ownership was shared with b
}
Just by curiosity, is it possible to declare a reference to an inner class in
an outer class :
class A{
private:
class B{
public:
B(double val):val_(val){}
private:
double val_;
};
public:
A(double val):b(B(val)){} /*problem*/
private:
B& b;
};
int main(){
A a(1.0);
}
It feels logic that it is impossible because I don't see how one can assign a
reference to a temporary variable. But I'd like to be sure. (I would like to
use a ref rather than a pointer to guarantee the presence of a B in A.)
Edit
As I had the question why I'd like to do that, here is my goal. Let's imagine
that the class B contains a lot of data and require a lot of memory. I don't
want to have many copy of B otherwise I will run out of memory. Now I have two
class C and D that both inherit of A. I want them to be related to the
same instance of B. I could do that with a pointer, but as said before I want
to make sure that at least a B exists somewhere, so I though that by using a
ref I would be able to guarentee that. I also would like B to be an inner
class so that I don't pollute my code. Thanks to your help, I now use a rvalue
reference and my code looks like this :
class A{
class B{
public:
B(double val):val_(val){}
private:
double val_;
};
public:
A(double val):b(B(val)){}
A(A const& a):b(a.b){}/*new problem*/
protected:
B&& b;
};
class C: public A{
public:
C(A const& a):A(a){}
};
class D: public A{
public:
D(A const& a):A(a){}
};
int main(){
A a(1.0);
C c(a);
D d(a);
}
but it doesn't compile.
No.
It'll compile if you use an rvalue reference:
class A
{
struct B {};
B&& b;
public:
A() : b(B()) {}
};
int main()
{
A a;
}
…but, annoyingly, this is a dangling reference by a special rule that prohibits the member b from extending the lifetime of that temporary B() as it otherwise might:
[C++11: 12.2/5]: [..] A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. [..]
Now, if B were public, and if the B object were passed in from somewhere else, then you'd have achieved your goal:
struct A
{
struct B {};
B& b;
A(B& b) : b(b) {}
};
int main()
{
A::B b;
A a(b);
}
(live demo)
But, failing that, I don't see what else you can do to achieve this.
It would seem to be of limited utility, though; just have an actual B member!
If you want an object to be shared between copied member, use a std::shared_ptr.
It's the only standard way to guarantee your B object will persistently exist for all the A objects that use it.
I have the following classes:
class A
{
public:
A() { x = 0; std::cout<<"A default ctor()\n"; }
A(int x_) { x = x_; std::cout<<"A normal ctor()\n"; }
int x;
};
class B
{
public:
B() { std::cout<<"B ctor()\n"; }
private:
std::string str;
};
and a function which creates an object B, taking an object A as parameter:
B
createB(const A& a) {
std::cout<<"a int: "<<a.x<<"\n";
return B();
}
if I design a class C, which has members of type A and B and constructs the B-object before A-object is constructed but using the A object to do so, this will compile without warnings but it will silently enter a bug:
class C
{
public:
C(): b(createB(a)), a(10) {}
private:
B b;
A a;
};
int main()
{
C c;
return 0;
}
Of course, the above example is a trivial one, but I've seen it in real world, in much more complex code (it's Friday, 8:30 PM and I just fixed this bug which led to segfaults).
How can I prevent this from happening?
I would agree with what others have suggested, namely that the onus is on the designer to ensure that objects are initialized before use. I see two ways of doing that in your case:
First (and easiest), reverse the order of a and b in the class definition:
class C
{
public:
C(): b(createB(a)), a(10) {}
private:
A a;
B b;
};
Second, you could move a to a base class if you want to really emphasize that it's initialization occurs before that of other members:
class CBase
{
protected:
CBase(): a(10) {}
protected:
A a;
};
class C : private CBase
{
public:
C(): b(createB(a)) {}
private:
B b;
};
I see three possible alternatives:
Require A to be constructed prior to constructing C:
class C
{
public:
C(const A& a) : a_(a), b_(a) {}
private:
A a_;
B b_;
};
Construct A prior to constructing 'B':
Delaying the construction of B until A is complete. This stops the undefined behavior from happening, but doesn't enforce proper behavior via the interface (as options 1 and 3 do)
class C
{
public:
C() : a_(/* construct as appropriate */)
{
b_.reset(new B(a_));
}
private:
A a_;
std::unique_ptr<B> b_;
};
If the design allows for it, have B contain (and expose) A.
This appears possible from the trivial example, but in real life may not be:
class B
{
public:
const A& my_a() {return a_;}
private:
// construct as appropriate (?)
A a_;
};
class C
{
private:
B b_;
};
I have a situation in which A has a reference to a class C defined inside B, and C has an instance of class B.
When I try to compile the code below, I get "field a has incomplete type". I assume this is because the compiler does not know how much memory it should allocate for an instance of A.
class A;
class B {
public:
class C {
A a;
};
};
class A {
A(const B::C& _c)
: c(_c)
{}
const B::C& c;
};
But when I try to compile this, I get "C in class B does not name a type":
class B;
class B::C;
class A {
A(const B::C& _c)
: c(_c)
{}
const B::C& c;
};
class B {
public:
class C {
A a;
};
};
How can I convince the compiler that B::C is a real type?
As an absolute guess, I notice there's one permutation you haven't tried:
class B {
public:
class C; // Forward declaration
};
class A {
A(const B::C& _c)
: c(_c)
{}
const B::C& c;
};
class B::C {
A a;
C() : a(*this) {} // Thanks Nim for pointing this out!
};
This is quite possibly illegal, but worth a shot I think. If it doesn't work, then I don't see any way around the problem.
The forward declaration for A doesn't serve a purpose: you can't declare an instance of an incomplete type.
As to B::C, I don't think you can use nested names in an incomplete type. Just don't nest C in B: as far as I know this doesn't give you any significant advantages* and stops you from forward declaring it.
*The only advantage I can think of is that you can define it in the private section, but then A would have no business with it in the first place.
In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing. So I'm trying to do something like this:
class A {
public:
A() : b(this) {}
private:
B b;
};
class B {
public:
B(A* _a) : a(_a) {}
private:
A* a;
};
Is there a way to ensure B always gets initialized with an A* without A holding a pointer to B?
Thanks
Try this:
class A;
class B {
public:
B(A *_a) : a(_a) {};
private:
A* a;
};
class A {
public:
A() : b(this) {};
private:
B b;
};
Since B is contained completely in A, it must be declared first. It needs a pointer to A, so you have to forward-declare A before you declare B.
This code compiles under more-or-less current versions of g++.
In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing.
You can store the pointer alright.
What you can't do is to try to get to the members/methods of A through the pointer in the constructor of B, since the parent instance might not be fully initialized at the point:
#include <iostream>
class Y;
class X
{
Y* y;
public:
X(Y* y);
};
class Y
{
X x;
int n;
public:
Y(): x(this), n(42) {}
int get_n() const { return n; }
};
X::X(Y* p): y(p)
{
//Now this is illegal:
//as it is, the n member has not been initialized yet for parent
//and hence get_n will return garbage
std::cout << p->get_n() << '\n';
}
int main()
{
Y y;
}
If you were to switch around the members in Y, so n would get initialized first, the constructor of X would print 42, but that is too fragile to depend on.