本周小贴士#188:注意智能指针函数参数

作为TotW#188最初发表于2020年12月10日

作者:Krzysztof Kosiński

这段代码有什么问题?

bool CanYouPetTheDog(const std::shared_ptr<Dog>& dog,
                     absl::Duration min_delay) {
  return dog->GetLastPetTime() + min_delay < absl::Now();
}

函数 CanYouPetTheDog 不会影响其 dog 参数的所有权,然而它的函数签名要求将其存储在 std::shared_ptr 中。这样做创建了对特定所有权模型的不必要依赖,尽管函数内部并不需要。这种依赖性阻止调用者使用其他模型,如 std::unique_ptr 或在栈上构造对象。

当所有权不受影响时,请使用引用或指针

通过使用引用,我们可以消除对特定所有权模型的依赖,并允许我们的函数与任何类型为 Dog 的对象一起工作。

bool CanYouPetTheDog(const Dog& dog, absl::Duration min_delay) {
  return dog.GetLastPetTime() + min_delay < absl::Now();
}

使用上述定义后,无论调用者的所有权模型如何,都可以调用该函数:

Dog stack_dog;
if (CanYouPetTheDog(stack_dog, delay)) { ... }

auto heap_dog = std::make_unique<Dog>();
if (CanYouPetTheDog(*heap_dog, delay)) { ... }

CustomPetPtr<Dog> custom_dog = CreateDog();
if (CanYouPetTheDog(*custom_dog, delay)) { ... }

如果函数修改传入的值,请传递一个可变引用或原始指针,并使用与上面展示的相同的惯用方法。

在函数修改所有权时使用智能指针

下面的代码为不同的智能指针参数提供了几个重载。第一个重载假设接受传入对象的所有权,第二个重载则在传入对象上添加了一个共享引用。这两个操作都取决于调用者如何处理 Dog 的所有权。无法接受位于栈上的 Dog 的所有权,因为无法从栈中取走所有权。

class Human {
 public:
  ...
  // 将 `dog` 的所有权转移给该 Human。
  // 有关接受 std::unique_ptr 值的理由,请参见提示 #117。
  void Adopt(std::unique_ptr<Dog> dog) {
    pets_.push_back(std::move(dog));
  }
  // 对 `cat` 添加一个共享引用。
  void Adopt(std::shared_ptr<Cat> cat) {
    pets_.push_back(std::move(cat));
  }

 private:
  std::vector<std::shared_ptr<Pet>> pets_;
  ...
};

结论

如果不传递或修改所有权,请避免在函数参数中使用智能指针。

你可能感兴趣的:(C++,Tips,of,the,Week,c++)