Following is another example of forward declaration, which might be useful if the application needs a self-sustaining array of objects which is able to add and remove objects from itself during run-time:
File a.h:
class A { public: static A *first, *last; A *previous, *next; A(); ~A(); };
File a.cpp:
#include "a.h" A *A::first=0, *A::last=0; // don't put the word static here, that will cause an error A::A() { if(first==0) first=this; //first A created previous=last; if(previous != 0) previous->next=this; last=this; next=0; } A::~A() { if(previous != 0) previous->next=next; if(next != 0) next->previous=previous; }
From : https://en.wikipedia.org/wiki/Circular_dependency#Self-reference_example
I think implementation of A
, has an issue. While first instance of A
is being constructed, if some other thread references A::first
, it will lead to unexpected behaviour. Please correct if I am wrong.
Also, how can this issue be resolved? Thanks.
This code is definitely non thread-safe as others stated in comments. Be it first object or not, it 2 threads try to create or delete a A object at the same time, you get undefined behaviour, because two different threads use and change same static value without any synchronization.
What could be done? As always to two same options:
And as @zvone noticed in comment, the destructor could make first
and last
become dangling pointers when you delete first or last element of the chain.
Destructor (non thread safe version) should be:
A::~A() {
if(previous != 0) previous->next=next;
if(next != 0) next->previous=previous;
if (first == this) first = next;
if (last == this) last = previous;
}
A thread-safe version could be:
File a.h
class A {
public:
static A *first, *last;
A *previous, *next;
static std::mutex mut;
A();
~A();
};
File a.cpp:
#include "a.h"
A *A::first=0, *A::last=0; // don't put the word static here, that will cause an error
std::mutex A::mut;
A::A() {
mut.lock()
if(first==0) first=this; //first A created
previous=last;
if(previous != 0) previous->next=this;
last=this;
next=0;
mut.unlock();
}
A::~A() {
mut.lock()
if(previous != 0) previous->next=next;
if(next != 0) next->previous=previous;
if (first == this) first = next;
if (last == this) last = previous;
mut.unlock();
}