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?

这是[basic.def.odr]/12.2

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::FooBarmoo:FooBar)。这违反了单一定义规则。无需诊断。