0

这是示例:

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我们得到 size 64Main.cpp我们得到 size 32。不仅sizeof不同 -operator new以不正确的 ( 32) 大小调用,而且构造函数将初始化 的大小64,这会导致内存损坏。

在 clang 和 msvc 中,这个程序的结果是:

Allocated size: 32
FoobarUser constructor, size: 64
Actual size: 32, member size: 32

这听起来很可疑,基本上意味着如果存在名称冲突,则不合格的名称是不可行的,因为根据包含顺序,它可能会导致本质上是不正确的程序。

但是我在 C++ std 中找不到任何可以说明任何无效/格式错误的代码的点。谁能帮我?

它真的是标准而不是一些复杂的大规模编译器问题(尽管我真的看不出编译器如何解决这种情况)?

4

1 回答 1

4

严格回答你的问题

我在 C++ std 中找不到任何可以说明任何无效/格式错误的代码的点。谁能帮我?

这是[basic.def.odr]/12.2

如果每个定义出现在不同的翻译单元中,并且定义满足以下要求,则程序中可以有多个类类型的定义[...]。给定这样一个名为 D 的实体在多个翻译单元中定义,则

  • D 的每个定义都应由相同的记号序列组成;和
  • 在 D 的每个定义中,对应的名称,根据 [basic.lookup] 查找,应指在 D 的定义中定义的实体,或应指同一实体,在重载决议和部分模板特化匹配之后( [temp.over]),除了名称可以引用

    • [ ...无关紧要]

在您的程序中,在您FoobarUser的两个翻译单元中都定义了,但其中的名称Foobar指的是——根据非限定查找规则——两个不同的实体(moo::test::FooBarmoo:FooBar)。这违反了单一定义规则。无需诊断。

于 2019-03-07T16:20:38.467 回答