Is the following Move operations legit, as in there is no UB. Instead of two swaps I want to implement a one swap of the 16 Bytes of 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_;
}
};
Note that MyString is clearly not trivially copyable. However I'm always swapping the internal bit representation of one MyString object with another.
Also, I'm fine with the operator= swaping with it's parameter. If xvalue is received (i.e lvalue that was std::moved, I'm fine with it carrying my "garbage"). So, please compare to this versions:
MyString(MyString&& s) noexcept : size_(0), str_(nullptr) {
std::swap(size_, s.size_);
std::swap(str_, s.str_);
}
And:
MyString& operator=(MyString&& s) {
std::swap(size_, s.size_);
std::swap(str_, s.str_);
return *this;
}
If this code is valid. Some would (rightfully) say this is a premature optimization, but can anyone claim one version is usually more efficient than the other or that typical compilers typically do this kind of optimization themselves? i.e turn the two swaps of 8Bytes into one swap of 16Bytes.
This version is defined according to the standard: https://compiler-explorer.com/z/xanvffGbG But isn't the straightforward code also valid? Can anyone quote the standard to prove it is valid or that it is not?