【问题标题】:Is using std::copy to work around strict aliasing safe?使用 std::copy 来解决严格的别名安全吗?
【发布时间】:2014-02-27 03:45:22
【问题描述】:

我有一个看起来像这样的函数:

template<typename T>
void some_function(T* buffer) {
    BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(unsigned int));

    unsigned int temporary_buffer;
    int result = some_c_api(&temporary_buffer);
    if(result == error)
        throw some_exception();

    // originally *buffer = reinterpret_cast<T&>(temporary_buffer), but this breaks 
    // strict aliasing
    std::copy( reinterpret_cast<char*>(&temporary_buffer), 
               reinterpret_cast<char*>(&temporary_buffer) + sizeof(T),
               reinterpret_cast<char*>(buffer));
}

在这里将两个不相关的缓冲区都转换为char* 并复制目标缓冲区可以容纳的字节数是否安全?我正在使用非 C++11 编译器 (gcc 4.1.2)。

我在重构一些代码时遇到了这个问题。原始代码没有此警告,因为它以void* 传递缓冲区。我认为这是非法的是否正确?

【问题讨论】:

  • temporary_buffer 真的是unsigned int 吗?你真的从unsigned ints 地址复制sizeof(T) 字节吗? sizeof(T) &lt;= sizeof(unsigned int)有什么保证吗?
  • 是的,确实是这样。函数开头有静态断言,确保sizeof(T) &lt;= sizeof(unsigned int)
  • 哎呀,完全错过了断言。

标签: c++ reinterpret-cast strict-aliasing type-punning


【解决方案1】:

这段代码看起来就像灾难等待发生。如果它因某种原因必须存在,则应填充静态断言和 cmets 以明确意图。

基本上,它只有在满足这些条件时才会起作用:

  • sizeof(T) &lt;= sizeof(unsigned int)(因为您正在从 unsigned int 复制到 T)。我看到这已经被断言了,很好。

  • T 是可简单复制的(根据 C++11 std::is_trivially_copyable 特征)。如果您的编译器不支持此特性的 Boost 等效项,只需记录要求即可。

只要满足这些就好了。这就是可复制的实际含义——它可以逐字节复制。我只是使用unsigned char 而不是char 来强调它是字节而不是字符的事实。

【讨论】:

  • 所有这些条件都成立(并在实际代码中强制执行)。这就是为丑陋的 C api 编写包装器时的样子。
猜你喜欢
  • 2021-07-04
  • 1970-01-01
  • 2018-12-14
  • 1970-01-01
  • 2021-05-23
  • 2010-09-20
  • 2012-04-24
  • 2018-03-04
  • 2023-02-02
相关资源
最近更新 更多