微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ 父对象丢失子对象的内部数据,与复制构造函数或按引用传递有关的错误?

如何解决C++ 父对象丢失子对象的内部数据,与复制构造函数或按引用传递有关的错误?

我的问题在下面的例子中得到了解释。如果在子对象填充其内部数据之前实例化了父对象,那么父对象会丢失其子对象的内部数据是很奇怪的。

代码一个 TicketService,它内部保存了一个 TicketStore 实例。 store 填充了 20 个 concerts。如果代码有以下顺序,一切都按预期进行,服务将可以在商店中看到20场音乐会。

TicketStore store;
Add20Concerts(store);
TicketService service(store);   // <- instantiating service after populating the store
// # of concerts in service=20
cout<<"# of concerts in service="<<service.GetNumberOfConcerts()<<endl;

但是,如果在填充商店之前实例化 service,它会在商店中看到零个音乐会。

TicketStore store;
TicketService service(store);   // <- instantiating service before populating the store
Add20Concerts(store);
// # of concerts in service=20
cout<<"# of concerts in service="<<service.GetNumberOfConcerts()<<endl;

为什么 servicestore 是空的?如果通过传递对 service 的引用来实例化 store,并且由于 store 将使用认的复制构造函数,那么底层的 concert_map_ 应该已经举办了 20 场音乐会。

更详细的代码框架如下,但上面几乎是我的困惑所在。

*******************************************************************************/
// ticket_service.h
class TicketService {
 public:

  explicit TicketService(const TicketStore& store) {
    store_ = store;  // should use the default copy constructor,which is a shallow copy of the original store
  }

  int32_t GetNumberOfConcerts() {
    return store_.GetStoreSize();
  }

 private:
  TicketStore store_;
};

*******************************************************************************/
// ticket_store.h
class TicketStore {
 public:
  TicketStore() {}

  void AddConcert(const Concert& concert) {
    concert_map_[concert.id()] = concert;
  }

  int32 GetStoreSize() const {
    return concert_map_.size();
  }

 private:
  absl::flat_hash_map<int64,Concert> concert_map_;
};

*******************************************************************************/
// main.cc
int main(int argc,char* argv[]) {
  TicketStore store;
  TicketService service(store);
  Add20Concerts(store);
  
  // if service is instantiated here,# of concerts in service=20.
  // TicketService service(store);
  
  cout<<"store size="<<store.GetStoreSize()<<endl; // store size=20
  
  // # of concerts in service=0 ??
  cout<<"# of concerts in service="<<service.GetNumberOfConcerts()<<endl;
}

void Add20Concerts(TicketStore &store) {
  for(int i=0; i<10; i++) {
    Concert concert;
    concert.set_id(i);
    store.AddConcert(concert);
  }
}

解决方法

TicketService 构造函数正在制作传入它的 TicketStore 对象的副本。在您的第二个示例中,创建 service 对象时该对象为空。创建 store 对象后对 main() 中的 service 对象所做的任何更改都不会反映在该副本中。

对于您正在尝试的内容,TicketService 对象需要持有对 TicketStore 对象的引用,例如:

class TicketService {
 public:
  explicit TicketService(const TicketStore& store) : store_(store) {}

  ...

 private:
  TicketStore& store_; // <-- reference!
};

UPDATE:为了避免任何可能的悬空引用,更好的选择是使用 std::shared_ptr 代替,例如:

class TicketService {
 public:
  explicit TicketService(std::shared_ptr<TicketStore> store) : store_(store) {}

 int32_t GetNumberOfConcerts() {
   return (store_) ? store_->GetStoreSize() : 0;
 }

 private:
  std::shared_ptr<TicketStore> store_;
};
void Add20Concerts(TicketStore &store) {
  for(int i=0; i<10; i++) {
    Concert concert;
    concert.set_id(i);
    store.AddConcert(concert);
  }
}

int main() {
  auto store = std::make_shared<TicketStore>();
  TicketService service(store);
  Add20Concerts(*store);
  
  cout<<"store size="<<store->GetStoreSize()<<endl;  
  cout<<"# of concerts in service="<<service->GetNumberOfConcerts()<<endl;
}

这样,在 TicketStore 和所有 TicketService 使用完毕之前,shared_ptr 对象保证不会被释放。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?