将赋值从新构造的对象移动到成员函数中的*this



实现一个reset()方法,该方法使用this中的一些成员来构造一个新对象,然后移动并将该对象分配给*this

问题:

  1. 这会引起任何问题吗?UB还是其他?(我觉得还好吗?(
  2. 还有更地道的方法吗

Destructor和move赋值运算符的实现只是为了证明正在发生的事情/真正的类两者都没有"规则5";没有遵循,因为这里不需要。

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numeric>
#include <ostream>
#include <random>
#include <vector>
struct Thing { // NOLINT Rule of 5 not followed, because debug only
public:
std::size_t      size;
std::vector<int> v;
explicit Thing(std::size_t size_) : size(size_), v(size_) {
std::cerr << "Thing constructorn";
std::iota(v.begin(), v.end(), 1);
}
~Thing() { std::cerr << "Thing destructorn"; } // purely for debugging
Thing& operator=(Thing&& other) noexcept {  // purely for debugging
std::cerr << "Thing Move Assignment operatorn";
size = other.size;
v    = std::move(other.v);
return *this;
}
void shuffle() {
std::shuffle(v.begin(), v.end(), std::mt19937{1}); // NOLINT fixed seed
}
void reset() {
// move assignment operator from a newly constructed object. Constructor uses SOME of the
// member variables of *this
*this = Thing(size);
}
friend std::ostream& operator<<(std::ostream& os, const Thing& t) {
os << "[";
const char* delim = "";
for (const auto& e: t.v) {
os << delim << e;
delim = ",";
}
return os << "]";
}
};
int main() {
std::cerr << "Before inital constructionn";
auto t = Thing(10);
std::cout << t << "n";
t.shuffle(); // somehow modify the object
std::cerr << "Before resetn";
std::cout << t << "n";
t.reset(); // reset using
std::cerr << "after resetn";
std::cout << t << "n";
}

输出:

Before inital construction
Thing constructor
[1,2,3,4,5,6,7,8,9,10]
Before reset
[10,1,3,6,8,5,7,4,2,9]
Thing constructor
Thing Move Assignment operator
Thing destructor
after reset
[1,2,3,4,5,6,7,8,9,10]
Thing destructor
  1. 这会引起任何问题吗?UB还是其他?(我觉得还好吗?(

只要move赋值和构造函数的实现方式符合您的要求,那么我认为没有问题。

  1. 有更惯用的方法吗

我会颠倒重用的方向。

explicit Thing(std::size_t size_) : size(size_), v(size_) {
reset();
}
void reset() {
v.resize(size_);
std::iota(v.begin(), v.end(), 1);
}

如果size应该总是与向量的大小匹配,那么我建议删除该成员,因为大小已经存储在向量中。这需要注意的是,在这种情况下,reset将无法将移动的from恢复到其早期的大小。但这通常是合理的限制。

最新更新