将引用参数传递给采用 unique_ptr 的通用引用的函数

时间:2021-07-21 14:08:26

标签: c++ reference unique-ptr move-semantics forwarding-reference

我有两个无法更改其签名的函数。第一个引用一个对象,而第二个引用一个指向同一对象的唯一指针的通用引用。我不确定如何将第一个参数传递给第二个。

我已经尝试过传递一个带有引用地址的新的唯一 ptr,但是由于引用是抽象的,编译器会抱怨未实现的方法。

这是一个例子:

// Example program
#include <iostream>
#include <memory>


class MyAbstractClass {
public:
  virtual void doSomething() = 0;    
};

class MyConcreteClass : public MyAbstractClass {
public:
  void doSomething() override {
    std::cout << "Hello I do something" << std::endl;
  }
};

class MyUserClass {
public:
  MyUserClass(MyAbstractClass& mac){
    // the line below doesn't work !!
    doSomethingElse(std::make_unique<MyAbstractClass>(&mac));
  }
  void doSomethingElse(std::unique_ptr<MyAbstractClass>&& mac){
    mac->doSomething();
  }  
};


int main() {
  MyConcreteClass mcc;
  MyUserClass muc(mcc);
}

1 个答案:

答案 0 :(得分:1)

您的编译器抱怨,因为 make_unique 在您尝试实例化的类型上调用 new,有效地复制了现有对象。当然,它不能那样做,因为这个类是抽象的。

除非您有办法保证传递给 MyUserClass 的引用是动态(“堆”)变量(并且其指针未被拥有等),否则您不能只在 { 中捕获其指针{1}} 然后在 unique_ptr 之后释放它。即使这是有保证的,就您所知,doSomethingElse 仍然可以尝试删除指针本身(除非您确切地知道它的作用)。当您通过右值引用传递它时,该对象在 doSomethingElse 返回后可能不再有效。

这意味着您必须制作对象的副本。但是,您无法制作普通副本。您需要复制整个非抽象底层对象。

如果您可以更改类的签名,添加一个虚拟的 doSomethingElse 方法就可以了。

如果不是,一个不完全可怕的解决方法可能是(尽管您需要事先知道所有继承 clone 的类型)MyAbstractClassswitch(typeid(mac))

相关问题