Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 静态析构函数的阶_C++ - Fatal编程技术网

C++ 静态析构函数的阶

C++ 静态析构函数的阶,c++,C++,如果类Foo有一个静态成员变量Bar,我希望Bar的析构函数只在Foo的析构函数的最后一个实例运行之后运行。下面的代码段(gcc 6.3,clang 3.8)不会出现这种情况: 为什么破坏的顺序与建造的顺序不同? 如果 ~()(代码)使用 fo::bar < /Cord> >这是删除后使用的一个.< /p> C++中的对象按顺序排列并按相反顺序销毁。首先是foo构造,然后是bar构造,然后执行main,然后bar被销毁,然后是foo。这就是你看到的行为。之所以出现此开关,是因为foo的构造函数

如果类
Foo
有一个静态成员变量
Bar
,我希望
Bar
的析构函数只在
Foo
的析构函数的最后一个实例运行之后运行。下面的代码段(gcc 6.3,clang 3.8)不会出现这种情况:

为什么破坏的顺序与建造的顺序不同?
如果<代码> ~()(代码)使用<代码> fo::bar < /Cord> >这是删除后使用的一个.< /p> C++中的对象按顺序排列并按相反顺序销毁。首先是
foo
构造,然后是
bar
构造,然后执行
main
,然后
bar
被销毁,然后是
foo
。这就是你看到的行为。之所以出现此开关,是因为
foo
的构造函数不构造
foo
,而是构造一个空的
unique\u ptr
,因此您无法在输出中看到
foo()
。然后用输出构建
bar
,在
main
中,在
Foo
构建很久之后创建实际的
Foo

我希望Bar的析构函数只能在Foo的析构函数的最后一个实例运行之后运行

不,作为
静态
数据成员,
Foo::bar
独立于
Foo
的任何实例

对于你展示的代码

static std::unique_ptr<Foo> foo; // no Foo created here

Bar Foo::bar; // Foo::bar is initialized before main(), => "Bar()"

int main(int argc, char **argv) {
    foo = std::make_unique<Foo>(); // an instance of Foo is created, => "Foo()"
} 

// objects are destroyed in the reverse order how they're declared
// Foo::bar is defined after foo, so it's destroyed at first => "~Bar()"
// foo is destroyed; the instance of Foo managed by it is destroyed too => "~Foo()"
static std::unique\u ptr foo;//这里没有创建Foo
巴福::巴;//Foo::bar在main()之前初始化,=>“bar()”
int main(int argc,字符**argv){
foo=std::make_unique();//创建了一个foo实例,=>“foo()”
} 
//对象的销毁顺序与声明顺序相反
//Foo::bar是在Foo之后定义的,因此它首先被销毁=>“~bar()
//福被摧毁;由它管理的Foo实例也被销毁=>“~Foo()”

这里的复杂之处在于,代码没有向
foo
的构造函数插入指令。发生的情况是,先构造
foo
,然后构造
foo::bar
。调用
make…unique
构造一个
Foo
对象。然后退出
main
,两个静态对象按与其构造相反的顺序被销毁:
Foo::bar
被销毁,然后
Foo
foo
的析构函数将销毁它所指向的
foo
对象,该对象是在
main

中创建的静态对象的生存期完全基于其定义的顺序。编译器对何时调用
Bar::Bar()
的“了解”不如调用
Bar::~Bar()

为了更好地说明这个问题,请考虑这个

class Foo;

struct Bar {
    Bar() {
        std::cout << "Bar()" << std::endl;
    }

    ~Bar() {
        std::cout << "~Bar()" << std::endl;
    }

    void baz() {}
};

struct Foo {
    Foo() {
        bar.baz();
        std::cout << "Foo()" << std::endl;
    }

    ~Foo() {
        std::cout << "~Foo()" << std::endl;
    }

    static Bar bar;
};

Foo foo;
Bar Foo::bar;

int main() {}
添加
std::unique\u ptr
会延迟
Foo::Foo()
在其主要构造之后的执行,从而使编译器产生“知道”何时调用
Bar::Bar()
的错觉


TLDR静态对象的定义应晚于其依赖项。在定义
bar
之前,定义
std::unique_ptr
和定义
Foo

同样是一个bug。一般来说,您不应该编写依赖于静态(或全局)数据的构造或销毁顺序的代码。这使得代码无法读取和维护(您可能更喜欢静态智能指针,或者 从
main
)调用显式初始化或启动例程。如果链接多个翻译单元,则不会指定顺序

请注意,它提供了and(带优先级)属性。我认为你应该避免使用它们。但是,
\uuu属性(构造函数)
对于插件初始化非常有用


在某些情况下,您还可以使用(至少在POSIX系统上)。我不知道这类注册函数是在析构函数之前还是之后调用的(我认为您不应该关心这个顺序)。

那么,全局函数是在
main()
实际退出之前销毁的?看起来不奇怪吗?如果
Foo
实例使用
static Bar
数据怎么办?@Alex它们在
main()
之后被销毁了?让我更清楚一点:
~Foo()
理论上可以使用
static Bar
@Alex-这就是我问这个问题的原因。@Alex然后你会得到一个销毁的对象。不要使用全局对象是个好主意;或者将
Foo::bar
的定义移到前面。是的-使用
unique\u ptr
是为了模仿我在更复杂的应用程序中的行为。因此,使用析构函数中的静态类成员是否不安全(即在
~bar()
中使用
Foo::bar
?听起来很疯狂。@我们的一个解决方法是使用
static std::unique\u ptr Foo=std::make_unique();
在全局
foo
声明中。另一个是在
main
的末尾写
foo=nullptr;
。如果没有帮助,请解释您想要实现什么。感谢您的回答。代码片段是一个小示例-在我的应用程序
foo()中
需要来自
argv
的参数,并且还需要传递信号,因此是全局的。您确定该标准规定了某些特定的顺序,尤其是几个翻译单元吗?@basilestrynkevitch不同的翻译单元没有顺序,因此这不适用。具有标准中的适当引号。Have您试图使
~Foo()成为
使用
数据?是的,这就是我提出这个问题的原因。它不会改变行为,并导致使用已销毁的对象。语言中没有任何机制可以确保在所有类实例被销毁后发生某些事情。类不会维护其实例或任何类似实例的计数器@n、 m.不,但是编译器知道在运行
Foo()
之前要构造
Foo::bar
(允许在
Foo()
中安全使用
Foo::bar
——人们希望这种行为也能
static std::unique_ptr<Foo> foo; // no Foo created here

Bar Foo::bar; // Foo::bar is initialized before main(), => "Bar()"

int main(int argc, char **argv) {
    foo = std::make_unique<Foo>(); // an instance of Foo is created, => "Foo()"
} 

// objects are destroyed in the reverse order how they're declared
// Foo::bar is defined after foo, so it's destroyed at first => "~Bar()"
// foo is destroyed; the instance of Foo managed by it is destroyed too => "~Foo()"
class Foo;

struct Bar {
    Bar() {
        std::cout << "Bar()" << std::endl;
    }

    ~Bar() {
        std::cout << "~Bar()" << std::endl;
    }

    void baz() {}
};

struct Foo {
    Foo() {
        bar.baz();
        std::cout << "Foo()" << std::endl;
    }

    ~Foo() {
        std::cout << "~Foo()" << std::endl;
    }

    static Bar bar;
};

Foo foo;
Bar Foo::bar;

int main() {}
Foo()
Bar()
~Bar()
~Foo()