示例:
Class *_obj1;
Class *_obj2;
void doThis(Class *obj) {}
void create() {
Class *obj1 = new Class();
Class obj2;
doThis(obj1);
doThis(&obj2);
_obj1 = obj1;
_obj2 = &obj2;
}
int main (int argc, const char * argv[]) {
create();
_obj1->doSomething();
_obj2->doSomething();
return 0;
}
这会创建2个对象,创建指向它们的指针,然后main()在每个对象上调用一个方法。 Class对象创建一个char *并存储C字符串“Hello!”在里面; ~Class()解除分配器释放内存。 doSomething()方法使用printf()打印出“buff:%s”。很简单。现在,如果我们运行它,我们得到这个:
的dealloc
Buff:你好!
Buff:¯ø_
显然堆栈对象在这里不起作用 - 显然当函数退出指针时_obj2指向堆栈中的某个位置。这就是我在上一个问题中使用堆对象的原因,人们告诉我这是“愚蠢的”。
所以,第一个问题是:如果如何将堆栈对象(obj2)转换为堆对象,以便在create()退出后不会释放它?我想要一个直接的答案,而不是正如许多人所做的那样,傲慢的“你做错了”。因为在这种情况下堆栈对象无法工作,所以堆对象似乎是唯一的方法。编辑:此外,转换回堆栈对象也很有用。
第二个问题:堆对象“错误”的具体示例是使用vector<string>*
运算符创建新的new
。 如果动态分配STL对象是错误的,那么正确的方法是什么?显然,如果你将它们创建为堆栈对象,它会因为它们被立即解除分配而失败,但我被告知(再次,非常动态分配它们的高级成员可能会破坏堆。那么正确的做法是什么?
答案 0 :(得分:9)
所以,第一个问题是:如果我如何将堆栈对象(obj2)转换为堆对象,那么在create()退出后它不会被解除分配?我想直接回答,
直接的答案是:你无法在堆栈和堆之间“转换”对象。你可以创建一个生活在另一个空间中的对象的副本,正如其他人指出的那样,但就是这样。
第二个问题:堆对象“错误”的具体示例是使用new运算符创建新的向量*。如果动态分配STL对象是错误的,那么正确的方法是什么?显然,如果你将它们创建为堆栈对象,它会失败,因为它们会被立即释放,但我被告知(再次,由一个非常高级别的成员),动态分配它们会破坏堆。
动态分配STL对象本身不会破坏堆。 (不知道你可能在哪里听说过。)
如果你想在你创建的函数之外使用堆栈分配的STL对象,你不能,因为对象所在的堆栈空间只在创建它的功能。
但是,您可以返回该对象的副本:
std::vector<char> SomeFunc()
{
std::vector<char> myvector;
// myvector.operations ...
return myvector;
}
正如我所说的,这将返回对象的副本,而不是原始对象本身 - 这是不可能的,因为包含该对象的堆栈在函数返回后展开。
另一个选择是让调用者传入一个引用/指针指向函数操作的对象,如果这对你的特定场景有意义的话:
void SomeFunc(std::vector<char>& destination)
{
// destination.operations ...
}
void AnotherFunc()
{
std::vector<char> myvector;
SomeFunc(myvector);
}
正如您所看到的,您仍然在堆栈上分配了所有内容,并且避免了依赖于复制构造函数返回对象副本的(有时是后果性的)开销。
答案 1 :(得分:4)
所以,第一个问题是:如果我如何将堆栈对象(obj2)转换为堆对象,那么在create()退出后它不会被解除分配?
这一行:
_obj2 = &obj2;
更改为:
_obj2 = new Class(obj2); // Create an object on the heap invoking the copy constructor.
我想要一个直接的答案,而不是像许多人那样傲慢的“你做错了”。
这就是你能得到的答案。显然你是C ++的新手,所以我确信这不会按照预期的方式工作,因为你可能在类“Class”的定义中犯了几个错误(顺便说一句名字)。
此外,转换回堆栈对象也很有用。
class obj3(*_obj2); // dereference the heap object pass it to the copy constructor.
第二个问题:堆对象“错误”的具体示例是使用new运算符创建一个新向量&lt; string&gt; *。如果动态分配STL对象是错误的,那么正确的方法是什么?
为什么要动态分配矢量。只需在本地创建它。
std::vector<std::string> funct()
{
std::vector<std::string> vecString;
// fill your vector here.
return vecString; // Notice no dynamic allocation with new,
}
使用new / delete正在使用像C这样的C ++。您需要阅读的是智能指针。这些是控制对象生命周期的对象,当对象超出范围时自动删除对象。
std::auto_ptr<Class> x(new Class);
这里x是一个智能指针(类型为auto_ptr),当它超出范围时,对象将被删除。但是你可以将auto_ptr返回给调用函数,它将被安全地转移出函数。它实际上比这复杂得多,你需要一本书。
显然,如果将它们创建为堆栈对象,则会失败,因为它们会立即被释放,
当它超出范围时,它会被分配。
但我被告知(再次,由一个非常高级别的成员),动态分配它们可能会破坏堆。
如果你做错了。鉴于你的知识很有可能。但很难验证,因为你没有提供Class的定义。
那么正确的方法是什么?
答案 2 :(得分:1)
您必须复制构造新的堆对象(Class * foo = new Class(obj2)
)或将堆栈对象分配给堆对象(*obj1 = obj2
)。
答案 3 :(得分:0)
唯一的方法是复制对象。
将声明更改为:
Class _obj2;
并指定:
_obj2 = obj2;
答案 4 :(得分:0)
您的堆栈对象是在create函数内创建的,并且一旦超出函数范围就会被释放。指针无效。
您可以将Class* obj2
更改为Class obj2
,并通过obj2 = obj2;
答案 5 :(得分:0)
获取堆栈变量的地址不会神奇地将其转移到堆中。您需要为您的类编写适当的复制构造函数并使用_obj2 = new Class(obj2);
。
对于STL容器,他们无论如何都要在堆上分配数据,为什么要在堆上分配容器呢?只要你需要它们,就把它们放在一个让它们保持活着的范围内。
答案 6 :(得分:0)
我认为你真的想问“我怎样才能返回在我的函数中创建的对象?”有几种有效的方法: