C ++非限定名称查找:不同cpp中的不同结构大小导致operator new分配比构造函数进程少的内存?

问题描述 投票:0回答:1

这是一个例子:

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++ sizeof one-definition-rule unqualified-name
1个回答
4
投票

严格回答你的问题

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

这是[basic.def.odr]/12.2

程序中可以有多个类类型的定义,只要每个定义出现在不同的翻译单元中,并且定义满足以下要求即可。鉴于这样一个名为D的实体在多个翻译单元中定义,那么

  • D的每个定义应由相同的令牌序列组成;和
  • 在D的每个定义中,根据[basic.lookup]查找的相应名称,应指D中定义的实体,或者在重载解析后和部分模板专门化匹配后应引用同一实体( [temp.over]),但名称可以参考 [......没有相关性]

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

© www.soinside.com 2019 - 2024. All rights reserved.