Two objects of same class referencing each other

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Two objects of same class referencing each other



There are objects of the same type always occuring in pairs. They are never alone, they are never more than two, like entangled particles.



I would like to implement this problem in C++ with two instances of the same class referencing each other. Creating the primary instance automatically creates the secondary one:


#include <iostream>
using namespace std;

class Particle

public:
// Constructs primary instance
Particle() :
partner_(Particle(*this))

cout << "Hi, I'm primary." << endl;


private:
// Constructs secondary instance
Particle(Particle & partner) :
partner_(partner)

cout << "Hi, I'm secondary." << endl;


Particle & partner_;
;

int main()

Particle two_friends;

return 0;



It doesn't compile:


main.cpp: In constructor ‘Particle::Particle()’:
main.cpp:10:14: error: cannot bind non-const lvalue reference of type ‘Particle&’ to an rvalue of type ‘Particle’
partner_(Particle(*this))
^~~~~~~~~~~~~~~



Is there a way to resolve this using references or do I have to use pointers instead?





Reference members cannot be bound to temporaries in a member initializer list.
– rsy56640
Aug 6 at 9:50





an alternative would be to have a class with two instances of Particle since they anyway always exist as pairs as you say.
– Anders
Aug 6 at 9:54






Aside - this is abusing the copy constructor... Anyone using Particle(Particle & partner) (including the compiler) in the future would expect it to make a copy of the object, and not whatever you're planning to do with it.
– UKMonkey
Aug 6 at 10:03


Particle(Particle & partner)





Useful rule of thumb: when you think you want a reference member, you still have some thinking left to do.
– molbdnilo
Aug 6 at 10:43




2 Answers
2



The reason it doesn't compile is that the compiler is saving you from making a mistake, you aren't allowed to pass a temporary object to a function (or constructor) as this is likely to cause bugs. In your case your temporary object would be destroyed at the end of your constructor and you'd only have one particle with a dangling reference to the now destroyed other object.



One solution would be to use shared and weak pointers (you need weak pointers or you'd have a circular reference).


#include <memory>

class Particle

public:
static std::shared_ptr< Particle > create()

std::shared_ptr< Particle > first( new Particle() );
std::shared_ptr< Particle > second( new Particle() );
// first will own second
first->partner = second;
// second will have a weak pointer to first
second->weakPartner = first;
return first;


std::shared_ptr< Particle > getPartner()

if (partner)

return partner;

return weakPartner.lock();


private:
Particle() ;
std::shared_ptr< Particle > partner;
std::weak_ptr< Particle > weakPartner;
;

int main()

std::shared_ptr< Particle > two_friends = Particle::create();



Keeping a shared_ptr to the first particle will keep the second alive but note that if you only have a shared_ptr to the second the first will be destroyed. You could avoid this by not using weak_ptr but then you would have to manually break the shared_ptr cycle before the particles would be destroyed.


shared_ptr


shared_ptr


weak_ptr


shared_ptr



There is a huge problem in your system first particle created on the stack, it's livetime is ok, but what with second? In your code it created as temp variable and destroyed in constructor, so reference inside class is useless any way. What I think you should do is use std::pair on another wrapper and set partners by yourself, like


struct ParticlePair
Particle first;
Particle second;
ParticlePair()

first.setPartner( second );
second.setPartner( first );




Good idea to make Particle constructor private and declare ParticlePair as a friend, in this case you will unable to create Particles alone.



In case if you will try to use pointers there is another problem: how to delete properly? Deleting first should delete second, but it means that deleting second should also delete first. Sooner or later you will delete already deleted pointer or delete object created on a stack.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard