gpt4 book ai didi

c++ - 如何防止 move 切片?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:03:41 28 4
gpt4 key购买 nike

当派生类实例作为右值 parent 引用传递给毫无戒心的方法时,后者可以合法地更改父类的内容,导致与存储在实际对象中的任何额外数据不一致。因此,为扩展而设计的类不能依赖默认的 move 语义。考虑一个简单的例子:

#include <memory>
#include <utility>
#include <iostream>

struct Resource {
int x;
Resource(int x_) : x(x_*x_) { }
};

struct A {
std::unique_ptr<Resource> ptr;

A(int x) : ptr{std::make_unique<Resource>(x)} { }
A(A&& other) = default; // i.e. : ptr(std::move(other.ptr)) { }
virtual ~A() = default;
// other elements of the rule of 5 left out for brevity

virtual int value() {
return ptr ? ptr->x : 0;
}
};

struct B : A {
int cached;

B(int x) : A(x), cached(A::value()) { }

int value() override {
return cached;
}
int value_parent() {
return A::value();
}
};

int main() {
B b{5};
std::cout << "Before: b.value() = " << b.value()
<< " (parent: " << b.value_parent() << ")\n";
A a = std::move(b);
std::cout << "After: b.value() = " << b.value()
<< " (parent: " << b.value_parent() << ")\n"; // INCONSISTENT!
}

为了将资源移交给最派生类,我想到了在move构造函数中使用虚函数获取moved-from资源:

... A {
A(A&& other) : ptr{std::move(other).yield()} { } /**/
virtual std::unique_ptr<Resource>&& yield() && {
return std::move(ptr);
}

... B {
virtual std::unique_ptr<Resource>&& yield() && override {
cached = 0;
return std::move(*this).A::yield(); /**/
}

这可以解决问题,但有两个问题,

  • 由于 C++“忘记”右值函数参数是 && 而很快变得不必要的冗长(请参阅标记的行中对 std::move 的需求/**/),
  • 当不止一个对象需要被yield时,不能轻易地泛化。

是否有更好/规范的解决方案?也许我错过了一些非常明显的东西。

最佳答案

您几乎不想复制 move 多态对象。它们通常位于堆上,并通过(智能)指针访问。对于复制,使用虚拟 clone 习惯用法;而且几乎没有理由 move 它们。因此,如果您的类有一个虚拟析构函数,那么大 5 的其他四个成员应该被删除d(或者被保护,如果您需要它们来实现您的虚拟克隆) .

但是在(主要是假设的)情况下,当您确实需要 move 一个多态对象,并且您只有一个基指针或引用时,您需要意识到 moving-from 也是对象公共(public)接口(interface)的一部分。所以它需要让整个对象保持一致的状态,而不仅仅是基础部分。所以你需要确保派生部分知道。不惜一切代价。通常你会想写一个专用的移出虚函数,并在你的 move 构造函数/赋值中调用它:

class Base {      
virtual void moved_fom() {} // do nothing for base
// some stuff
// members of the big 5
virtual ~Base() = default;
Base (Base&& other) {
// do the move
other->moved_from();
}
// etc
};

现在任何派生都可以对从脚下拉出的基础部分做出正确 react 。

关于c++ - 如何防止 move 切片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54791124/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com