通过智能指针固定对象指针成员的赋值

Fixing assignment of an object's pointer members via smart pointers

提问人:Eduardo 提问时间:6/25/2018 最后编辑:curiousguyEduardo 更新时间:6/27/2018 访问量:27

问:

我正在学习有关 C++ 14 中智能指针的更多信息。

考虑以下 MWC:

#include <iostream>
#include <string>
#include <memory>

class House {
 public:
  House &operator=(const House &house) = default;
  House(const House &house) = default;
  House(): id_habitants_(nullptr), num_habitants_() {}
  explicit House(size_t num_habitants) {
    if (num_habitants > 0) {
      num_habitants_ = num_habitants;
      id_habitants_ = new int[num_habitants_];
      if (id_habitants_ != nullptr) {
        for (size_t id = 0; id < num_habitants_; ++id) {
          id_habitants_[id] = 1;
        }
      }
    }
  }
  void Print() {
    if (id_habitants_ != nullptr) {
      for (size_t id = 0; id < num_habitants_; ++id) {
        std::cout << id_habitants_[id] << ' ';
      }
      std::cout << std::endl;
    } else {
      std::cout << "<empty>" << std::endl;
    }
  }
  ~House() {
    if (id_habitants_ != nullptr) {
      delete [] id_habitants_;
    }
    num_habitants_ = 0;
  }
 private:
  int *id_habitants_;
  size_t num_habitants_;
};

int main() {
  std::cout << "Testing unique_ptr.\n" << std::endl;

  std::cout << "Using a dumb House class..." << std::endl;
  std::cout << "Creating House h1 with 3 habitants..." << std::endl;
  House h1(3);
  std::cout << "IDs of h1's 3 habitants:" << std::endl;
  h1.Print();
  std::cout << "Creating House h2 with 0 habitants..." << std::endl;
  House h2;
  std::cout << "IDs of h2's 0 habitants:" << std::endl;
  h2.Print();
  std::cout << "Default-assigning h1 to h2..." << std::endl;
  h2 = h1;
  std::cout << "IDs of h2's new 3 habitants:" << std::endl;
  h2.Print();
  std::cout << "Destroying h1..." << std::endl;
  h1.~House();
  std::cout << "IDs of h2's new 3 habitants:" << std::endl;
  h2.Print();
}

在不修改类的默认复制构造函数和默认赋值运算符的情况下,如何通过智能指针确保赋值期间指针行为正确?House

在第一次尝试时,似乎使用将是要走的路。我可以创建一个新类:std::unique_ptr

class SmartHouse {
 public:
  SmartHouse &operator=(const SmartHouse &shouse) = default;
  SmartHouse(const SmartHouse &shouse) = default;
  SmartHouse(): id_habitants_(nullptr), num_habitants_() {}

  explicit SmartHouse(size_t num_habitants) {
    if (num_habitants > 0) {
      num_habitants_ = num_habitants;
      id_habitants_ = std::unique_ptr<int[]>(new int[num_habitants_]);
      if (id_habitants_) {
        for (size_t id = 0; id < num_habitants_; ++id) {
          id_habitants_[id] = 1;
        }
      }
    }
  }
  void Print() {
    if (id_habitants_) {
      for (size_t id = 0; id < num_habitants_; ++id) {
        std::cout << id_habitants_[id] << ' ';
      }
      std::cout << std::endl;
    } else {
      std::cout << "<empty>" << std::endl;
    }
  }
  ~SmartHouse() {
    num_habitants_ = 0;
  }
 private:
  std::unique_ptr<int[]> id_habitants_;
  size_t num_habitants_;
};

,我无法真正将一个唯一的指针复制到另一个指针。有道理,对吧?这在某种程度上违背了它独特的目的。即这不会编译:

SmartHouse sh1(3);
SmartHouse sh2;
sh2 = sh1;

但是我可以指定一个移动赋值运算符,并在赋值时移动成员,从而在赋值时将指向数据的所有权转移到左侧对象:unique_ptr<int[]>

class SmartHouse {
  SmartHouse &operator=(SmartHouse &&SmartHouse) = default;
}
...
SmartHouse sh1(3);
SmartHouse sh2;
sh2 = std::move(sh1);
sh1.~SmartHouse();
sh2.Print();

核心问题:这有意义吗?是否有更好的方法来增强指针成员变量的赋值?

完整的 MWE

数组 C++11 unique-ptr 赋值运算符 move-assignment-operator

评论

0赞 Igor Tandetnik 6/25/2018
您似乎想要一个深层副本。执行此操作的“智能指针”称为 。作为奖励,它也使它变得没有必要,因为它会跟踪自己的大小。id_habitants_std::vector<int>num_habitants_
0赞 curiousguy 6/27/2018
1) 对 0 个居民的情况不做任何事情。2) 可以拼写 参见 std::unique_ptr::resetSmartHouse(size_t num_habitants)id_habitants_ = std::unique_ptr<int[]>(p)id_habitants_.reset(p)
0赞 curiousguy 6/27/2018
3)你需要意识到,与C或90年代早期的原始C++不同,在现代C++分配函数(如)中,失败时抛出异常,它们不会返回空指针,除了特殊的无异常版本()。参见 std::nothrownew int[num_habitants_]new (std::nothrow) some_type
0赞 curiousguy 6/27/2018
4)你不能只是这样做,因为你会在没有活动对象的情况下退出块。在退出块之前,您需要重新创建对象。(你只是不调用自动对象的析构函数。5) 你想用那个析构函数完成什么? 当一个对象被摧毁时,它的子对象也会被摧毁。h1.~House();h1~SmartHouse() { num_habitants_ = 0; }

答: 暂无答案