这个 reinterpret_cast 原则上和/或实践上有问题吗?

Ast*_*ngs 4 c++ language-lawyer c++17

采取以下措施:

#include <vector>
#include <string>
#include <type_traits>

int main()
{
    std::vector<std::string> vec{"foo", "bar"};
    for (auto& el : vec)
       el.std::string::~string();

    auto& aliased = reinterpret_cast<
       std::vector<
          std::aligned_storage_t<sizeof(std::string), alignof(std::string)>
       >&>(vec);
    aliased.clear();
}
Run Code Online (Sandbox Code Playgroud)

(当然,从更复杂的代码中缩减——我们通常不会std::string在这样一个简单的测试用例中以这种方式管理一个简单的向量)

这个程序有未定义的行为吗?我认为我们不能别名vector<T1>asvector<T2>,即使T1T2兼容。

如果是这样,这是否会在运行时产生实际影响?

假设编译器中没有禁用严格别名。

有趣的是,GCC 9.2.0 没有给我任何警告-fstrict-aliasing -Wstrict-aliasinglive demo)。

Nic*_*las 9

这个程序有未定义的行为吗?

绝对地。您正在vector<string>通过对某个不相关类型的引用来访问类型的对象。那是 UB,违反了严格的别名规则

如果是这样,这是否会在运行时产生实际影响?

UB 表示运行时的行为未定义。是的。

  • @AsteroidsWithWings:您将问题标记为“语言律师”。这意味着您对符合 C++ 标准的 C++ 行为感兴趣,而不是它在某些无界且不可知的编译器系列上的假设行为。 (3认同)
  • @AsteroidsWithWings 还强烈认为,有一些臭名昭著的 UB 代码在编译器更新之前“按预期工作”。它发生在 Linux 内核上,它也会发生在你身上。不要依赖未定义的行为,即使它“恰好现在在您的系统上运行” (2认同)
  • @AsteroidsWithWings 关于严格别名规则的一点是,它们允许更自由地重新排序内存访问。你的编译器可能会决定重新排序这样简单的东西,例如 `vec[42] = "foo"; cout &lt;&lt; aliased[42];`,实际上很可能会这样做。毕竟,内存加载 `aliased[42]` 需要时间,因此应该尽早安排,并且严格的别名规则意味着 `vec[42] = "foo"` 不会影响加载的结果。或者确实如此? (2认同)