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

C++ parent object loses the internal data of the child object, something wrong related to copy constructor or passing by reference?

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

该代码有一个 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;

为什么 service 有一个 store 是空的?如果 service 是通过传递对 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 对象时该对象为空。在创建 service 对象后对 main() 中的 store 对象所做的任何更改都不会反映在 copy.

对于您正在尝试的操作,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 都使用完它。