如何解决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;
为什么 service
的 store
是空的?如果通过传递对 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 举报,一经查实,本站将立刻删除。