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

时间:2017-11-10 22:51:54

标签: c++ move-semantics

面对一种情况,不知道该怎么做......这是我现在的代码:

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&传递?

4 个答案:

答案 0 :(得分:4)

我认为您要找的类型可能是void SomeBusinessLogic(std::unique_ptr<IMyDbAccessor>)

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

答案 1 :(得分:4)

  

我不喜欢它,因为它不够富有表现力。

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

  

我想

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

表示SomeBusinessLogic想拥有一个传递的对象

这不是右值引用所代表的。右值引用意味着dbacc将引用编译器在实际呼叫站点创建的临时对象,或者调用者通过std::move()传递的预先存在的对象。无论哪种方式,在dbacc退出后,SomeBusinessLogic()引用的对象都不会再被使用,因此SomeBuinessLogic()被允许&#34;窃取&#34;由dbacc引用的对象持有的任何内部数据的所有权,而不是复制它。这与对象本身的所有权无关。这仍然严格依赖于来电者。

  

所以main应该是

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

但当然不可能......

您要找的是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释放了被破坏时指向的内存。这就是它的独特之处#34;当您看到std::unique_ptr时,您知道所有者是谁。并且按值将std::unique_ptr对象传递给函数意味着它仅存在于函数的生命周期中。

因此,这种方法使非常明确dbacc本身,而不是调用者,拥有IMyDbAccessor对象的独占所有权,并在{{{{{}}时释放该对象。 1}}退出(除非SomeBusinessLogic()决定SomeBusinessLogic() std::move()dbacc之外的另一个std::unique_ptr

  

或者我的感觉是错误的,我不应该SomeBusinessLogic()SomeBusinessLogic所有权负责,所以最好将其作为IMyDbAccessor传递?

我愿意,是的。除非有一些令人信服的理由const IMyDbAccessor&必须取消来自呼叫者的所有权。

答案 2 :(得分:0)

执行SomeBusinessLogic(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

答案 3 :(得分:0)

如果您正在寻找提供反馈的方式“嘿,我会修改此变量!”在呼叫位置,我强烈推荐常量指针。

然后你有:

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

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