避免对象切片和使用shared_ptr
Avoiding object slicing and using shared_ptr
现在我正在开发一个搜索节点程序。我的代码在下面,我实际上想搜索一个特定的子节点。为了避免对象切片,我使用了一个指针,但指针可能是null_ptr。那么我该如何避免这个问题呢。我不确定它的问题是什么?为了避免新实例属性,main()中的父对象实例应声明为自c++11以来支持的shared_ptr?
#include <iostream>
using namespace std;
class Parent {
public:
Parent() { name = "Parent"; }
virtual void print() {
cout << "Parent::print()" << endl;
}
string name;
};
class Child1 : public Parent {
public:
Child1() { name = "Child1"; }
virtual void print() override{
cout << "Child1::print()" << endl;
}
};
class Child2 : public Parent {
public:
Child2() { name = "Child2"; }
virtual void print() override{
cout << "Child2::print()" << endl;
}
};
class Manager {
public:
void getChild(int i, Parent* obj) {
if(i==0) {
cout << "sest child1" << endl;
obj = (&child1);
} else {
cout << "sest child2" << endl;
obj = (&child2);
}
}
Child1 child1;
Child2 child2;
};
int main()
{
// object slicing?
// Parent obj;
// Manager manager;
// manager.getChild(1, obj);
// obj.print();
Parent* obj;
Manager manager;
manager.getChild(1, obj);
obj->print();
}
由于分段错误,我的代码被破坏了。
$ a.out D
sest child2
[1] 5457 segmentation fault ./work/derived/a.out D
void getChild(int i, Parent* obj)
这个函数签名告诉我们,函数接受一个整数和指向对象的指针。两者都通过值传递:
如果您有一个对象,比如在地址42,那么您将有效地传递数字42作为第二个参数。
在函数内部,参数充当变量,由于在这种情况下它们不是常量,因此可以对它们进行修改。所以当你写的时候
obj = &child1;
您只更改了一个局部变量的状态,例如从前面提到的42更改为其他地址,例如24。所有这些都不会影响调用方作为第二个参数给出的指针。
您想要实现的是拥有一个"out"参数。为此,你需要一个指向你想要改变的东西的指针。在您的情况下,您想要更改指针,因此需要一个指向指针的指针:
void getChild(int i, Parent * * obj_ptr)
要将其设置为一个值,您需要取消引用它:
*obj_ptr = &child1;
但是在这种情况下,我不会使用out参数,因为您可以从函数中返回值,所以只需返回指针:
Parent* getChild(int i) {
// ...
return &child1;
}
// in main
Parent* node = manager.getChild(1);
关于std::shared_ptr
:您应该考虑谁拥有指针指向的实例。也就是说,谁负责破坏它们并释放相关内存。在您的案例中,子实例是管理器实例的一部分。因此,管理器实例拥有它们并将处理它们。shared_ptr
适用于(希望)极少数情况,即您不知道实例需要多长时间。所以你分享所有权,让最后一个所有者负责破坏和释放。
我不完全清楚你在这里真正需要什么样的所有权。你想要某种遍历吗,即子实例是其他子实例的父母(或者你术语中的管理者)?还是您只需要访问成员?那我就不使用指针了,只使用引用。
您正在按值将指针obj
传递给getChild
(获取副本)。如果将本地obj
指针更改为指向不更改主作用域中obj
指针的其他对象。主作用域中的obj
指针仍然指向垃圾。
由于obj
是out参数,因此编写getChild
的一种更惯用的方法是使用返回值:
Parent* getChild(int i) {
if(i==0) {
cout << "sest child1" << endl;
return &child1;
}
cout << "sest child2" << endl;
return &child2;
}
你可以这样使用:
Manager manager;
auto obj = manager.getChild(1);
obj->print();
不,您不应该将shared_ptr
用于主作用域中的obj
。至少不像现在写的那样。目前,child1
和child2
由Manager
所有,因为它们由值成员变量所有。除了Manager
,您不希望其他人删除它们。
但也许这不是你想要的设计。也许您的意图更像原型模式,其中getChild
返回child1
或child2
的克隆,该克隆应该由调用方拥有。
我认为你不应该在堆栈上分配child1和child2,而是应该使用新的运算符在头上分配。第二个修改是在一些不同的函数中获得任何新的内存分配时,将用户指针指向指针。修改后的程序如下:
#include <iostream>
#include <string>
using namespace std;
class Parent {
public:
Parent() { name = "Parent"; }
virtual void print() {
cout << "Parent::print()" << endl;
}
string name;
};
class Child1 : public Parent {
public:
Child1() { name = "Child1"; }
virtual void print() {
cout << "Child1::print()" << endl;
}
};
class Child2 : public Parent {
public:
Child2() { name = "Child2"; }
virtual void print() {
cout << "Child2::print()" << endl;
}
};
class Manager {
public:
Manager()
{
child1 = new Child1;
child2 = new Child2;
}
void getChild(int i, Parent** obj) {
if(i==0) {
cout << "sest child1" << endl;
*obj = child1;
} else {
cout << "sest child2" << endl;
*obj = child2;
}
}
Child1 *child1;
Child2 *child2;
};
int main()
{
Parent* obj;
Manager manager;
manager.getChild(1, &obj);
obj->print();
}
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 无法使用 libtool 将 -shared 参数传递给 g++
- boost::shared_ptr和std::shared-ptr的同居
- 我可以用std::shared_ptr而不是boost::shared-ptr构建boost库吗
- shared-ptr-C++shared_ptr与unique_ptr用于资源管理