c++ - 使用匿名命名空间结构 : is this safe? 的 pimpl 习语

标签 c++ namespaces pimpl-idiom incomplete-type

我的一个队友经常使用 pimpl 的变体,他是这样使用的:

Foo.h:

namespace { struct Impl; }

class Foo
{
public:
  Foo();
  ~Foo();

  void Bar(int n);
  /* ... */

private:
  std::unique_ptr<Impl> _impl;
};

这里发生的事情是他向前声明实现类在匿名命名空间中。然后他将在 Foo.cpp 中定义 Impl 类。

因此结构::Impl 的定义将可用于Foo.cpp 的翻译单元。其他代码包括 Foo.h 将引发警告,因为它们显然无法访问 Foo.cpp 中定义的 ::Impl。但是,我们不需要它们 - 这是一个仅用于 Foo.cpp 的类;我们不希望它在其他地方可见或为人所知。

虽然我们肯定会遇到 .cpp 文件包含多个 header 的情况,每个 header 都声明自己的 ::Impl 结构,但这些实际上并不冲突,因为这些结构从未在其各自的翻译单元之外使用。

tl;dr:这看起来很奇怪,会发出警告,看起来好像会导致冲突,但似乎确实有效。


综上所述,我不喜欢在我们的代码中嵌入如此深的引发警告的东西(它包含的头文件越多,删除它就越难。)它也只是一个 < em>ton 警告。

我的队友支持这一点,因为它很简单,保持代码定义简单,并让我们在所有代码中使用简短、一致的类名 Impl

我不是编码约定的坚持者;如果这对我们的用例来说是好的做法,我不介意。但我希望感到安心,因为它是安全且可维护的,并且不会在某些时候在我们面前爆炸。

最佳答案

Foo 类违反了 ODR。每个 cpp 文件都认为其唯一的 ptr 包含不同的类型。

ODR 违规会使您的程序格式错误,无需诊断。

你的程序可能会工作,但它的行为完全没有被 C++ 标准指定。

可能导致的实际问题是编译器可能会在您的脚下发生变化,并且当前未定义的行为(“它似乎可以工作”)将更改为其他东西(“强制转换意外失败”、“损坏的类型表”、“链接器无法链接”,“编译器证明类永远不能在其实现的翻译单元之外使用,并删除函数中的所有代码,就好像它们运行它会是 UB。”)作为示例,但没有限制如何它可能会变得疯狂。

有时做 UB 是有好处的,值得冒险。我在这里看到零 yield 。

创建一个 namespace FooImplFoo_details 并在其中填充 Impl

关于c++ - 使用匿名命名空间结构 : is this safe? 的 pimpl 习语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39684438/

相关文章:

c++ - if (condition) try {...} 在 C++ 中合法吗?

c++ - QLineEdit 圆角?

c++ - 给出数字列表以确定哪个组合为您提供给定值

c++ - 我可以在不修改 QWidget 子类 PIMPL 样式的情况下包装它吗

c++ - 没有参数与调用匹配的匹配函数调用

找不到带有命名空间的 PHP 类

c++ - 命名空间类和结构

python:与本地类名混淆

c++ - Pimpl 成语内存使用

c++ - 模板中的 pimpl 成语;哪个智能指针?