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; }
发件人:https://en.wikipedia.org/wiki/Circular_dependency#Self-reference_example
我认为 A
的实现有问题。在构造 A
的第一个实例时,如果其他线程引用 A::first
,则会导致意外行为。如果我错了,请纠正。
还有,这个问题怎么解决?谢谢。
最佳答案
正如其他人在评论中所述,这段代码绝对是非线程安全的。无论是否是第一个对象,如果有 2 个线程同时尝试创建或删除 A 对象,您会得到未定义的行为,因为两个不同的线程在没有任何同步的情况下使用和更改相同的静态值。
可以做什么?一如既往地有两个相同的选项:
- 记录类(至少是构造函数和析构函数)不是线程安全的。由于它们,调用者有责任确保只有一个线程可以同时访问 A 对象。换句话说,这意味着 A 仅在单线程程序中是安全的。
- 在类本身内部添加同步以使其线程安全。当创建和销毁操作静态成员时,您需要一个用于类的所有对象的全局互斥体,换句话说,类静态对象。
正如@zvone 在评论中注意到的那样,当您删除链中的第一个或最后一个元素时,析构函数可以使 first
和 last
成为悬挂指针。
析构函数(非线程安全版本)应该是:
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.h
class A {
public:
static A *first, *last;
A *previous, *next;
static std::mutex mut;
A();
~A();
};
文件 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();
}
关于c++ - 在构造函数中引用此指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34267426/