很久之后我又回到了C++,继承了一个代码库,其中一部分具有以下代码的结构。我有两个对象,
Wrapped
和Wrapper
,正如所料,Wrapper
包裹Wrapped
。有两个工厂方法 make_Wrapper
和 make_Wrapped
,它们返回指向相应对象的指针。
在下面的代码中,我观察到,使用
Case1
的 shared_ptr
不起作用,而使用普通 C++ 指针的 Case2
则有效。我所说的“不起作用”,是指在 Case1 中 nz_=10
中的值 wrapped
被垃圾替换,而在 Case2 中它等于 10。我可以通过 wrapper.nz_
在 main
中打印 outside_wrapper->print()
的值来检查这一点。
我认为这是因为shared_ptr指向的对象在这个函数
make_Wrapper
退出后被删除了。我说得对吗?
通过
shared_ptr
将对象从 make_Wrapper
传递到 Wrapper
构造函数的正确方法是什么?
#include <iostream>
#include <memory>
#include <functional>
// this is struct which is to be wrapped
struct Wrapped {
int nz_;
Wrapped(int nz):nz_(nz) {}
inline virtual void destroy() { delete this; };
};
// this is the wrapper
struct Wrapper {
Wrapper(Wrapped& wrapped):wrapped_(wrapped){}
Wrapped& wrapped_;
inline virtual void destroy() { delete this; };
void print() {
std::cout << "from wrapper: wrapped_.nz_=" << wrapped_.nz_<<std::endl;
}
};
// factory function which returns pointer to wrapped object
Wrapped* make_Wrapped(int nz) {
return new Wrapped(nz);
}
// factory function which returns pointer to wrapper object
Wrapper* make_Wrapper(int nz) {
// Case 1
// following line does not work - I think the object pointed to by the shared_ptr is deleted after this function exits
std::shared_ptr<Wrapped> wrapped(make_Wrapped(nz), std::mem_fun(&Wrapped::destroy));
// Case 2
// following line works
// Wrapped *wrapped = new Wrapped(nz);
std::cout<<" from make_Wrapper "<<(*wrapped).nz_<<std::endl;
return new Wrapper(*wrapped);
}
int main() {
int nz=10;
char tempbuffer[80];
std::shared_ptr<Wrapper> outside_wrapper(make_Wrapper(nz), std::mem_fun(&Wrapper::destroy));
outside_wrapper->print();
std::cout << "Enter something to continue ..." << std::endl;
std::cin >> tempbuffer;
return 0;
}
一旦一个对象被
shared_ptr
包裹,当指向它的最后一个 shared_ptr
被销毁时,它就会被销毁,这发生在 make_Wrapper
的末尾。
解决方案:
让 Wrapper 存储
shared_ptr
而不仅仅是一个参考。
struct Wrapper {
Wrapper(std::shared_ptr<Wrapped> wrapped) :wrapped_(wrapped) {}
std::shared_ptr<Wrapped> wrapped_;
inline virtual void destroy() { delete this; };
void print() {
std::cout << "from wrapper: wrapped_.nz_=" << wrapped_->nz_ << std::endl;
}
};
// factory function which returns pointer to wrapper object
Wrapper* make_Wrapper(int nz) {
// Case 1
// following line does not work - I think the object pointed to by the shared_ptr is deleted after this function exits
std::shared_ptr<Wrapped> wrapped(make_Wrapped(nz), std::mem_fun(&Wrapped::destroy));
std::cout << " from make_Wrapper " << (*wrapped).nz_ << std::endl;
return new Wrapper(wrapped);
}