如果类Foo
具有静态成员变量Bar
,我希望Bar
的析构函数仅在Foo
的析构函数的最后一个实例运行之后运行。下面的代码片段(gcc 6.3,clang 3.8)不会发生这种情况:
#include <memory>
#include <iostream>
class Foo;
static std::unique_ptr<Foo> foo;
struct Bar {
Bar() {
std::cout << "Bar()" << std::endl;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
};
struct Foo {
Foo() {
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
static Bar bar;
};
Bar Foo::bar;
int main(int argc, char **argv) {
foo = std::make_unique<Foo>();
}
输出:
Bar()
Foo()
~Bar()
~Foo()
为什么破坏的顺序不是与建筑相反的?
如果~Foo()
使用Foo::bar
,则在删除后使用。
答案 0 :(得分:11)
在C ++中,对象按出现的顺序构造,并以相反的顺序进行破坏。首先是foo
构造,然后是bar
构造,然后执行main
,然后bar
被破坏,然后foo
。这是你看到的行为。出现切换是因为foo
的构造函数没有构造Foo
,它会构造一个空的unique_ptr
,因此您无法看到Foo()
在输出中。然后使用输出构建bar
,并在main
中在Foo
构建之后创建实际的foo
。
答案 1 :(得分:2)
我希望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()"
的任何实例。
对于您展示的代码,
onEachFeature: function (feature, layer) {
var popupContent = "<p>I started out as a GeoJSON " +
feature.geometry.type + ", but now I'm a Leaflet vector!</p>";
if (feature.properties && feature.properties.popupContent) {
popupContent += feature.properties.popupContent;
}
$('#sidebar>.sidebar_content').html(popupContent);
$('.custom-div').html(popupContent);
}
答案 2 :(得分:2)
这里的复杂性是代码没有检测foo
的构造函数。会发生什么是foo
首先被构造,而Foo::bar
被构造。对make…unique
的调用会构造一个Foo
对象。然后main
退出,两个静态对象按其构造的相反顺序销毁:Foo::bar
被破坏,然后foo
。 foo
的析构函数会破坏它指向的Foo
对象,即main
中创建的对象。
答案 3 :(得分:1)
静态对象的生命周期完全基于其定义的顺序。编辑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() {}
打印
Foo()
Bar()
~Bar()
~Foo()
std::unique_ptr
在main中构建Foo::Foo()
之后推迟Bar::Bar()
,让人觉得编译器“知道”何时调用bar
。
TLDR静态对象的定义应晚于其依赖项。在定义std::unique_ptr<Foo>
之前,定义Foo
和定义 from("ftps://{{ftp.username}}@{{ftp.host}}/{{ftp.importDirectory}}?password="
+ "{{ftp.password}}&readLock=changed&move={{ftp.processed}}"
+ "&moveFailed={{ftp.failed}}"
+ "&securityProtocol=SSL&execProt=P&execPbsz=0&passiveMode=true")
.idempotentConsumer(header("camelFileAbsolutePath"),
MemoryIdempotentRepository.memoryIdempotentRepository(200))
.to("bean:ftpConsumer?method=consumeMethod")
答案 4 :(得分:0)
通常,您不应编写依赖于构造或破坏静态(或全局)数据的顺序的代码。这使得代码难以理解且不可维护(您可能更喜欢静态智能指针,或者
显式初始化或从main
调用的启动例程。当您链接多个翻译单元时,未指定AFAIK订单。
请注意,GCC提供了init_priority
和constructor
(带优先级)属性。我相信你应该避免使用它们。但是,__attribute__(constructor)
is有用的inside插件,用于插件初始化。
在某些情况下,您还可以使用atexit(3)(至少在POSIX系统上)。我不知道这些注册函数是在析构函数之前还是之后调用的(我认为你不应该关心那个顺序)。