C ++中的虚拟移动构造函数

Virtual move constructor in C++

刚遇到一个情况,不知道该怎么办...这是我现在的代码:

class IMyDbAccessor {
 public:
  int getSum();  // quite important for my case that it is not const.
                 // it does some caching. Of course I may use mutable,
                 // but actually it is not that important here.
};

void SomeBusinessLogic(IMyDbAccessor& dbacc) { /* implementation */ }

int main(int argc, char** argv) {
    MyDbAccessor acc(argv);
    SomeBusinessLogic(acc);
}

不喜欢,因为表现力不够。我想要

void SomeBusinessLogic(IMyDbAccessor&& dbacc) { /* implementation */ }

表明SomeBusinessLogic想要拥有一个传递的对象,所以main应该看起来像

int main(int argc, char** argv) {
    MyDbAccessor acc(argv);
    SomeBusinessLogic(std::move(acc));
}

但这当然是不可能的...有人知道这是什么原因吗?对我来说,这很有意义。

或者我的感觉不对,我不应该让SomeBusinessLogicIMyDbAccessor所有权负责,所以最好把它作为const IMyDbAccessor&?

我想你要找的类型大概是void SomeBusinessLogic(std::unique_ptr<IMyDbAccessor>)?

表示所有权正在转移,并接受派生对象

做一些业务逻辑(std::forward(acc))。

例如:

#include <iostream>
#include <utility>

class IMyDbAccessor {
public:
  virtual int getSum() = 0;

};

class MyDbAccessor : public IMyDbAccessor {
public:
    virtual int getSum() { return 0; }

};

void SomeBusinessLogic(IMyDbAccessor&& dbacc) { std::cout << dbacc.getSum() << std::endl; }

int main(int argc, char** argv) {
    MyDbAccessor acc;
    SomeBusinessLogic(std::forward<MyDbAccessor>(acc));
}

在这里试试: http://cpp.sh/7pbrm

如果您正在寻找一种在调用位置提供反馈的方法"Hey I will modify this variable!",我强烈推荐 const 指针。

那么你有:

void SomeBusinessLogic(IMyDbAccessor* const dbacc) { /* implementation */ }

int main(int argc, char** argv) {
    MyDbAccessor acc;
    SomeBusinessLogic(&acc);
}

I don't like it, because it is not expressive enough.

我觉得很有表现力。通过引用传递对象意味着该函数可以对调用者提供的现有对象进行操作,而不是对副本进行操作。不用担心管理所有权。

I would like to have

void SomeBusinessLogic(IMyDbAccessor&& dbacc) { /* implementation */ }

to show that SomeBusinessLogic wants to own a passed object

这不是右值引用所代表的。右值引用意味着 dbacc 将引用编译器在实际调用站点创建的 临时 对象,或者调用者使用 [= 传递的预先存在的对象16=]。无论哪种方式,dbacc 引用的对象预计在 SomeBusinessLogic() 退出后不再使用,因此 SomeBuinessLogic() 被允许 "steal" 任何 的所有权dbacc 引用的对象持有的内部数据 ,而不是复制它。这与对象本身的所有权无关。这仍然严格取决于调用者。

so main should look like

int main(int argc, char** argv) {
    MyDbAccessor acc(argv);
    SomeBusinessLogic(std::move(acc));
}

But of course it is impossible...

你要找的是std::unique_ptr:

void SomeBusinessLogic(std:::unique_ptr<IMyDbAccessor> dbacc) { /* implementation */ }

int main(int argc, char** argv) {
    std::unique_ptr<IMyDbAccessor> acc(new MyDbAccessor(argv));
    SomeBusinessLogic(std::move(acc));
}

或:

int main(int argc, char** argv) {
    SomeBusinessLogic(std::make_unique<MyDbAccessor>(argv));
}

一次只能有一个 std::unique_ptr 保存给定的指针,因为 std::unique_ptr 在销毁时释放指向的内存。这就是它 "unique" 的原因。当您看到 std::unique_ptr 时,您 知道 所有者是谁。将 std::unique_ptr 对象按值传递给函数意味着它仅在函数的生命周期内存在。

因此,这种方法非常清楚地表明 dbacc 本身,而不是调用者,拥有 IMyDbAccessor 对象的独占所有权,并将释放当 SomeBusinessLogic() 退出时那个对象(除非 SomeBusinessLogic() 决定 std::move() dbaccSomeBusinessLogic() 之外的另一个 std::unique_ptr

Or my feelings are wrong and I should not make SomeBusinessLogic responsible for IMyDbAccessor ownership, so it's better to pass it as a const IMyDbAccessor&?

我愿意,是的。除非有一些令人信服的理由 SomeBusinessLogic() 必须从调用者手中夺走所有权。