【问题标题】:General swap implementation in terms of byte swap字节交换方面的一般交换实现
【发布时间】:2016-03-07 01:59:49
【问题描述】:

标准库中通用交换的当前实现类似于

template <class T>
void swap(T& a, T& b) {
  T c(move(a));
  a = move(b);
  b = move(c);
}

我想知道是否可以改为执行以下操作。

template <class T>
void swap(T& a, T& b) {
  unsigned char x;
  auto pa = reintepret_cast<unsigned char*>(&a);
  auto pb = reintepret_cast<unsigned char*>(&b);
  auto pc = pa + sizeof(a);
  while (pa != pc) {
    x = *pa;
    *pa = *pb;
    *pb = x;
    ++pa, ++pb;
  }
}

我认为这种实现在空间使用方面更好,因为它只需要一个字节。

【问题讨论】:

  • 不管它可能有也可能没有其他问题,时间性能可能会更差,真的有理由将一般情况限制为仅使用一个字节的临时空间吗?只有在最受限制的系统上才有必要这样做。
  • 一次一个字节的方法将起作用,但仅适用于 POD 类型。对于无法简单复制的类型,它不会做正确的事情。
  • 对于不能随意简化为单字节移动的原子/易失类型也失败了。
  • “在空间使用方面更好,因为它只需要一个字节” - CPU 寄存器可能是 4 或 8 字节宽:处理较小的大小将是 效率较低。作为一般规则,当您刚刚学习语言时(正如问题所暗示的那样),请相信编译器会比您更好地优化,除非分析证明您必须参与其中。
  • @JeremyFriesner :您的意思是可以简单复制的类型。 PODness 是 C++03 的要求。

标签: c++ c++14 swap c++-standard-library


【解决方案1】:

在交换类时需要考虑许多注意事项。对于 POD 类型,交换字节可以正常工作。然而,更复杂的类可能依赖于字节交换不尊重的不变量。例如,考虑对成员变量的引用:

struct Foo {
    Foo() : bar{}, barRef{bar} {};
    int  bar;
    int& barRef; // Expected to refer to the neighboring `bar`
};

int main()
{
    Foo f{};
    {
        Foo g{};
        byte_swap(f, g);
    }
    // `f` is now invalid: `f.barRef` is pointing to garbage
}

【讨论】:

  • 那么,你基本上是在说byte_swap()不尊重const-modified成员?
  • @Lingxi 不完全是。我是说成员的原始值只是使类有效的一部分。可能存在字节交换不遵守的假设和不变量。
  • 我没有明白“交换字节没问题”这句话的确切含义。它具有相同的性能,还是只是一个正确的操作?
  • @Amadeus 我的意思是这是一个正确的操作。至于性能,您可以自己对不同类型的交换进行基准测试。我怀疑会有很大的改进,但我自己从未测试过。
【解决方案2】:

您必须考虑到每个类都可以定义当一个实例被它自己的复制或移动时应该发生什么。有时一个类可能会做一些不同的事情,然后只是移动它的字节。也许该类存储了一个指向同一实例成员的指针。仅仅复制字节就会破坏实例。


我也认为这不会有太大的不同。当应用程序需要更多 60 个字节时,这并不明显。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    相关资源
    最近更新 更多