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
都使用完它。
我的问题在下面的例子中得到了解释。如果在子对象填充其内部数据之前实例化父对象,那么父对象会丢失其子对象的内部数据,这很奇怪。
该代码有一个 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
都使用完它。