为 MyString 实现按位交换

问题描述 投票:0回答:1

以下 Move 操作是否合法,因为没有 UB。 我想实现 16 字节 MyString 的一次交换,而不是两次交换。

class MyString {
    std::size_t size_;
    char* str_;
    
    MyString(const char* str, std::size_t len): size_(len), str_(size_ ? new char[size_+1] : nullptr) {
      if (size_) {
        memcpy(str_, str, len+1);
      } 
    }

    void bitwise_swap(MyString* l, MyString* r) {
        constexpr size_t size = sizeof(MyString);
        alignas (MyString)  char tmp[size]; // is alignas even necessary? 
        std::memcpy(&tmp, l, size);
        std::memcpy(l, r, size);
        std::memcpy(r, &tmp, size);
    }
    
public:    
    MyString(const char* str = ""): MyString(str, strlen(str)) {
    }
    
    MyString(MyString&& s) noexcept : size_(0), str_(nullptr) {
        bitwise_swap(this, &s);
    }
    
    MyString& operator=(MyString&& s) {
        bitwise_swap(this, &s); 
        return *this;
    }
    
    ~MyString() {
      delete[] str_;
    }
};

请注意,MyString 显然不可轻易复制。然而,我总是将一个 MyString 对象的内部位表示与另一个对象交换。

另外,我很乐意使用operator= 与它的参数交换。如果收到 xvalue(即 std::moved 的左值,我可以接受它携带我的“垃圾”)。所以,请与这个版本进行比较:

MyString(MyString&& s) noexcept : size_(0), str_(nullptr) {
   std::swap(size_, s.size_);
   std::swap(str_, s.str_);
}

并且:

MyString& operator=(MyString&& s) {
   std::swap(size_, s.size_);
   std::swap(str_, s.str_);
   return *this;
}

如果此代码有效。 有些人(理所当然地)会说这是一种过早的优化,但是有人可以声称一个版本通常比另一个版本更有效,或者典型的编译器通常自己进行这种优化吗?即将两次 8Bytes 的交换变成一次 16Bytes 的交换。

c++ c++11 language-lawyer move-semantics trivially-copyable
1个回答
0
投票

请注意,MyString 显然不可轻易复制。然而,我总是将一个 MyString 对象的内部位表示与另一个对象交换。

不可平凡复制类型上的

std::memcpy
是 UB。具体来说 [basic.types.general]/2 指定仅针对普通可复制类型将底层字节从对象复制到字符数组并返回到相同类型的对象的行为。

© www.soinside.com 2019 - 2024. All rights reserved.