【问题标题】:How to use a unique_ptr as an argument to a function that requires a base class as parameter如何使用 unique_ptr 作为需要基类作为参数的函数的参数
【发布时间】:2017-07-16 18:35:45
【问题描述】:

我正在学习使用托管指针,特别是 unique_ptr。

我已经实现了这些简单的类,但是函数 makeAnimalNoise() 不起作用,即使我认为我传递了正确的参数。

函数 makeAnimalNoise() 有什么问题?这个函数的正确参数应该是什么?还是定义本身有误?

class Animal{
public:
  Animal(){
    cout<<"An animal is born"<<endl;
  }
  virtual ~Animal(){
    cout<<"An animal dies"<<endl;
  }
  virtual void doAnimalStuff()=0;
};

class Dog: public Animal{
public:
  Dog(){
    cout<<"A dog is born"<<endl;
  }
  ~Dog() {
    cout<<"A dog dies"<<endl;
  }
  void doAnimalStuff() override {
    cout<<"I'm a dog"<<endl;
  }
};

class Cat: public Animal{
public:
 Cat(){
   cout<<"A cat is born"<<endl;
 }
~Cat() {
   cout<<"A cat dies"<<endl;
 }
void doAnimalStuff() override {
  cout<<"I'm a cat"<<endl;
 }
};

void makeAnimalNoise(unique_ptr<Animal>an){
  an->doAnimalStuff();
}

int main(){
  unique_ptr<Animal>Dog=unique_ptr<Dog>(new Dog());
  unique_ptr<Animal>Cat=unique_ptr<Cat>(new Cat());
  makeAnimalNoise(Dog); //doesn't work here
  makeAnimalNoise(Cat); //doesn't work here
}

【问题讨论】:

  • unique_ptr 应该是唯一的 并传达所有权的概念。如果您正在做一些涉及复制它们的事情,那么您就做错了。

标签: c++ polymorphism unique-ptr


【解决方案1】:

makeAnimalNoise的参数声明为传值;但是std::unique_ptr不能被复制;你可以像这样移动它

unique_ptr<Animal> dog(new Dog);
unique_ptr<Animal> cat(new Cat);
makeAnimalNoise(std::move(dog));
makeAnimalNoise(std::move(cat));

【讨论】:

  • 你确定可以做到这一点。但这真的是理想的行为吗?是否应该仅仅因为发出声音而杀死动物?
  • 我认为 makeAnimalNoise(dog.get()) 和 makeAnimalNoise(cat.get()) 更好,而且效果很好,但首先你必须更改函数的参数。
  • @BenjaminLindley 好吧,这取决于 OP 的意图(即复制/移动操作是否可以接受)。对于这个问题,我想他只是在询问std::unique_ptr 的用法。
【解决方案2】:

您不想将所有权转移到您的 makeAnimalNoise 函数中。智能指针只能由责任的所有者使用;你绝对应该用智能指针替换all你的代码。

你的函数应该只是一个参考:

void makeAnimalNoise(Animal& an) {
  an.doAnimalStuff();
}

在通话现场:

makeAnimalNoise(*Dog);
makeAnimalNoise(*Cat);

重复一遍:只有当指针的所有权是 API 的主体时,智能指针才应该出现在 API 中。当只对被指针的感兴趣时,使用引用或普通指针参数。

换一种说法:智能指针是一种管理职责的工具,而不是用于传递值或实现引用语义的工具。

【讨论】:

  • 感谢您的回答。我一直在进行一些实验,并且使该功能按我的意愿工作。我将函数的参数更改为:void makeAnimalNoise(Animal*an)。在主函数中,我这样做了:makeAnimalNoise(doggy.get())。这被认为是正确的还是安全的?
  • @Drako:也可以。与往常一样,指针参数可能会传递一个空值,因此与引用参数的语义略有不同。选择最适合您的。
猜你喜欢
  • 2013-07-02
  • 2017-11-09
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 1970-01-01
相关资源
最近更新 更多