我最近痛苦地意识到Static Initialization Order Fiasco。我想知道,如果规则"初始化顺序未在翻译单元中定义"仍然适用于父类中的静态成员,子类中的静态成员需要这些成员。
例如,假设我们(为简洁起见,除了所有#guard和include)
// a.h
class A {
static int count;
static int register_subclass();
};
// a.cpp
int A::count = 0;
int A::register_subclass() {
return count ++;
}
然后是A
,
// b.h
class B : public A {
static int id;
};
// b.cpp
int B::id = A::register_subclass();
这里有两个转换单元,其中一个静态对象在初始化中依赖于另一个静态对象...它似乎可能是静态初始化顺序fiasco的一个实例。
我的问题是:实际上是否安全??
也就是说,我保证B::id
在A::count
初始化之前不会包含从A
复制的垃圾?根据我自己的测试, imagesForVideo = []
imagesForVideoCGI = []
var timesArray:[NSValue] = []
let generator:AVAssetImageGenerator = AVAssetImageGenerator(asset: sourceAsset)
for var i = 0; i < numberOfFrames - 1; i++ {
var actualTime : CMTime = CMTimeMake(0, 0)
let duration:CMTime = CMTimeMake(Int64(i), Int32(30))
let frameRef:CGImageRef = try! generator.copyCGImageAtTime(duration, actualTime: &actualTime)
let tempImage:UIImage = UIImage(CGImage: frameRef)
let nsDuration = NSValue.init(CMTime: duration)
timesArray.append(nsDuration)
imagesForVideoCGI.append(frameRef)
imagesForVideo.append(tempImage)
}
generator.generateCGImagesAsynchronouslyForTimes(timesArray, completionHandler: {(_, im:CGImage?, _, _, e:NSError?) in self.addingImages(im)})
似乎总是先被初始化,但我不确定如何在初始化顺序中引入噪声,以增加失败的可能性,如果行为未定义。
答案 0 :(得分:3)
通常,依赖基类和派生类的静态初始化顺序是不安全的。无法保证...
if (req.method.toLowerCase() === 'get') {
var fileUrl = 'https://yeketakclub.storage.googleapis.com/images/yeketak.club-4rjngDhckqZ9ZBmG2fsv.jpeg';
var filename = fileUrl.split('/').pop();
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
request(fileUrl).pipe(res);
} else {
res.writeHead(404);
res.end('Nein Nein :))');
}
...
的静态初始化将在A
之前发生。这是static initialization order fiasco的定义。
您可以在首次使用时使用构造 idiom:
B
更新:然而,说,博格丹在评论中指出
根据标准中的[3.6.2],保证了该特定示例中的初始化顺序。它与继承无关,但事实上
// a.h class A { private: static int& count(); protected: static int register_subclass(); }; // a.cpp int& A::count() { static int count = 0; return count; } int A::register_subclass() { return count()++; } // b.h class B : public A { public: static int id; }; // b.cpp int B::id = A::register_subclass();
的初始化是常量初始化,这保证在动态初始化之前完成,是A::count
使用的。
但是,除非你完全掌握这些内容,否则我建议你在第一次使用习语时使用构造。
在这种情况下可以,但在多线程上下文中要注意B::id
之类的函数。如果多个线程同时调用它可能会发生任何事情
答案 1 :(得分:0)
我想知道,如果“翻译单元未定义初始化顺序”的规则仍然适用于父类中静态成员,而子类中的静态成员需要这些规则。
是的,确实如此。
静态数据成员与继承层次结构(或者,实际上,它们的封装类)的唯一方式是它们的完全限定名称;他们的定义和初始化完全没有意识到/不关心这个。