这是一个例子:
Main.cpp
:
#include "MooFoobar.h"
#include "MooTestFoobar.h"
#include "FoobarUser.h"
namespace moo::test::xxx {
struct X
{
void* operator new(const size_t size);
FoobarUser m_User;
};
void* X::operator new(const size_t size)
{
printf("Allocated size: %zd\n", size);
return malloc(size);
}
} // namespace moo::test::xxx
int main()
{
new moo::test::xxx::X;
printf("Actual size: %zd, member size: %zd\n", sizeof(moo::test::xxx::X), sizeof(moo::test::xxx::FoobarUser));
return 0;
}
MooFoobar.h
:
namespace moo {
struct Foobar
{
char m_Foo[64];
};
} // namespace moo
MooTestFoobar.h
:
namespace moo::test {
struct Foobar
{
char m_Foo[32];
};
} // namespace moo::test
FoobarUser.h
:
#include "MooFoobar.h"
namespace moo::test::xxx {
struct FoobarUser
{
FoobarUser();
~FoobarUser();
Foobar m_Foobar;
};
} // namespace moo::test::xxx
FoobarUser.cpp
:
#include "FoobarUser.h"
#include <cstdio>
moo::test::xxx::FoobarUser::FoobarUser()
: m_Foobar()
{
printf("FoobarUser constructor, size: %zd\n", sizeof(*this));
}
moo::test::xxx::FoobarUser::~FoobarUser()
{}
所以这里发生了什么:取决于包括不合格名称的顺序在不同的类型解决,在FoobarUser.cpp
我们得到大小64
,在Main.cpp
我们得到大小32
。不仅sizeof
不同 - operator new
被称为不正确的(32
)大小,但构造函数将初始化64
的大小,导致内存损坏。
在clang和msvc中,该程序的结果是:
Allocated size: 32
FoobarUser constructor, size: 64
Actual size: 32, member size: 32
这听起来非常腥,基本上意味着如果存在名称冲突,不合格的名称就不会发生,因为根据包含顺序,它可能导致本质上是错误的程序。
但我在C ++标准中找不到任何可以说任何无效/格式错误的代码。谁能帮我?
它真的是标准的,而不是一些精心设计的批量编译器问题(虽然我不能真正看到编译器如何解决这种情况)?
严格回答你的问题
我在C ++标准中找不到任何可以说任何无效/格式错误的代码。谁能帮我?
程序中可以有多个类类型的定义,只要每个定义出现在不同的翻译单元中,并且定义满足以下要求即可。鉴于这样一个名为D的实体在多个翻译单元中定义,那么
- D的每个定义应由相同的令牌序列组成;和
- 在D的每个定义中,根据[basic.lookup]查找的相应名称,应指D中定义的实体,或者在重载解析后和部分模板专门化匹配后应引用同一实体( [temp.over]),但名称可以参考 [......没有相关性]
在你的程序中,FoobarUser
在你的两个翻译单元中都被定义,但是Foobar
这个名字指的是---根据不合格的查找规则---两个不同的实体(moo::test::FooBar
和moo:FooBar
)。这违反了单一定义规则。无需诊断。