C++ 不合格名称查找:不同 cpp 中的不同结构大小导致 operator new 分配的内存少于构造函数进程?
C++ unqualified name lookup: different structure size in different cpp's leading to operator new allocating less memory than constructor processes?
示例如下:
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++ std 中找不到任何点可以说明任何 invalid/ill-formed 代码。谁能帮帮我?
这真的是标准问题,而不是一些复杂的大规模编译器问题(虽然我真的看不出编译器如何解决这种情况)?
认真回答你的问题
I can't find any point in the C++ std that would say any of that invalid/ill-formed code. Can anyone help me?
There can be more than one definition of a class type [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
- each definition of D shall consist of the same sequence of tokens; and
in each definition of D, corresponding names, looked up according to [basic.lookup], shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization ([temp.over]), except that a name can refer to
- [ ... nothing of relevance]
在你的程序中,FoobarUser
在你的两个翻译单元中都定义了,但是名称Foobar
里面指的是---根据不合格查找规则---两个不同的实体(moo::test::FooBar
和 moo:FooBar
)。这违反了单一定义规则。无需诊断。
示例如下:
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++ std 中找不到任何点可以说明任何 invalid/ill-formed 代码。谁能帮帮我?
这真的是标准问题,而不是一些复杂的大规模编译器问题(虽然我真的看不出编译器如何解决这种情况)?
认真回答你的问题
I can't find any point in the C++ std that would say any of that invalid/ill-formed code. Can anyone help me?
There can be more than one definition of a class type [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
- each definition of D shall consist of the same sequence of tokens; and
in each definition of D, corresponding names, looked up according to [basic.lookup], shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization ([temp.over]), except that a name can refer to
- [ ... nothing of relevance]
在你的程序中,FoobarUser
在你的两个翻译单元中都定义了,但是名称Foobar
里面指的是---根据不合格查找规则---两个不同的实体(moo::test::FooBar
和 moo:FooBar
)。这违反了单一定义规则。无需诊断。