【问题标题】:Structs with the same name/namespace but different members具有相同名称/命名空间但成员不同的结构
【发布时间】:2018-11-05 21:26:41
【问题描述】:

我看到了一些我在这篇帖子 vector of structs inline initialization. braced-init-list 中描述的奇怪行为

我希望消除未定义行为的一种可能来源。我有以下两个类A 和B,它们都前向声明struct Foo,但cpp 文件定义了如下的实际结构。

// This is A.h
namespace app {
    struct Foo;
    class A {
    private:
        std::vector<Foo> fooList;
    };
}

// This is A.cpp
struct app::Foo {
    std::string first;
    std::string second;
    unsigned flag;
};


// This is B.h
namespace app {
    struct Foo;
    class B {
    private:
        std::vector<Foo> fooList;
    };
}

// This is B.cpp
struct app::Foo {
    std::string first;
    std::string second;
    bool flag;
    float value;
};

请注意,结构 Foo 在 cpp 文件 A.cpp、B.cpp 中有不同的成员。 A 和 B 类永远不会暴露成员 fooList。是否有可能因为前向声明完全相同,在文件A.h 和B.h 的结构Foo 中,生成的代码可能使用其中一个或另一个。这可以解释我在链接问题中看到的问题。

换句话说,当对B.cpp 中调用的结构Foo 使用花括号初始化列表时,是否可以保证使用B.cpp 中定义的Foo,或者同样可能使用Foo A.cpp中定义的也可以用吗?

即使在我写这篇文章的时候,我也立即意识到这个实现是一种不好的做法,因为Foo 本身是类A 和B 的内部,并且确实应该在类的私有部分中声明自己。

【问题讨论】:

  • 请注意,C++ 标准不允许 vector 的不完整类型。所以你的代码不符合标准。
  • @juanchopanza 只要构造函数和析构函数可以访问定义,就可以了。

标签: c++ c++11 struct


【解决方案1】:

这违反了 ODR(一个定义规则)。

程序格式错误,不需要诊断。

如果您这样做,C++ 标准绝对允许任何行为。它可以“工作”,它可以选择一个并丢弃另一个,它可以工作直到你重新链接,它可以格式化你的硬盘。

我在一个真实的项目中做到了这一点;我们有一个矩阵头,如果它支持浮点或双精度,您可以在包含它之前定义标记。

当我们从未在同一个 DLL 中使用这两个版本时,这“有效”。然后我们使用了这两个版本。

编译器会根据一组巧合为结构选择一个大小,并会根据一组稍微不同的巧合选择一个构造函数或其他构造函数。我们得到了大量的内存损坏。但只是有时在某些版本上。

我们通过将代码包装在名称中包含标量类型的命名空间中来快速“修复”它,然后using 将它们带入外部命名空间。

【讨论】:

  • 有趣。出于某种原因,我相信如果编译器在程序集中发现重复的定义,它会向我指出并且不会按原样接受它。
  • @cplusplusrat UB 也意味着编译器可以决定发出诊断(例如警告)。但问题是编译器一次只处理一个文件。它不会在两个不同的文件中看到双重定义(除非它们被包含在另一个文件中)。而且链接器根本不需要处理类,因此很难实际检测到此类错误。
猜你喜欢
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 2010-11-12
  • 2012-08-27
  • 2018-06-25
相关资源
最近更新 更多