我看到这篇文章vector of structs inline initialization. braced-init-list中描述了一些奇怪的行为
我希望消除这种不确定行为的一种可能来源。我有以下两个类A
和B
,它们都向前声明struct Foo
,但cpp文件定义了如下的实际结构。
// This is A.h
namespace app {
struct Foo;
class A {
private:
std::vector<Foo> fooList;
};
}
// This is A.cpp
struct app::Foo {
std::string first;
std::string second;
unsigned flag;
};
// This is B.h
namespace app {
struct Foo;
class B {
private:
std::vector<Foo> fooList;
};
}
// This is B.cpp
struct app::Foo {
std::string first;
std::string second;
bool flag;
float value;
};
注意,struct
Foo
在cpp文件A.cpp
,B.cpp
中具有不同的成员。类A
和B
从不公开成员fooList
。由于前向声明完全相同,因此是否有可能,在结构A.h
的文件B.h
和Foo
中,生成的代码可以使用另一个。这可以解释我在链接问题中看到的问题。换句话说,在对在
Foo
中调用的struct B.cpp
使用braced-init-list的同时,是否保证将使用在Foo
中定义的B.cpp
,或者是否有可能也可以使用在Foo
中定义的A.cpp
?即使在撰写本文时,我也立即意识到这种实现是一种不好的做法,因为
Foo
本身在A
和B
类的内部,并且实际上应该在该类本身的私有(private)部分中声明。 最佳答案
这违反了ODR(一个定义规则)。
该程序格式不正确,无需诊断。
如果这样做,C++标准绝对允许任何行为。它可以“工作”,可以选择一个并丢弃另一个,可以工作直到重新链接,然后可以格式化硬盘。
我是在一个真实的现场项目中完成的;我们有一个矩阵 header ,可以在其中包含 token (如果它支持float或double),那么可以在其中定义 token 。
在我们从未在同一个DLL中使用两个版本的情况下,这种方法“有效”。然后我们使用了两个版本。
编译器将基于一组巧合为结构选择一个大小或其他大小,并根据一组稍有不同的巧合选择一个构造函数或其他构造函数。我们有大量的内存损坏问题。但仅在某些版本上才有。
我们通过将代码包装在名称包括标量类型的 namespace 中来快速“修复”它,然后using
将它们带入外部 namespace 。