如何在堆栈和堆对象之间进行转换

时间:2011-02-20 17:54:09

标签: c++ stack heap

示例:

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对象是错误的,那么正确的方法是什么?显然,如果你将它们创建为堆栈对象,它会因为它们被立即解除分配而失败,但我被告知(再次,非常动态分配它们的高级成员可能会破坏堆。那么正确的做法是什么?

7 个答案:

答案 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的定义。

  

那么正确的方法是什么?

  1. 了解您应该使用堆栈对象的原因
  2. 了解智能指针是什么。
  3. 了解如何使用智能指针控制对象的生命周期。
  4. 了解不同类型的智能指针。
  5. 查看关注点的分离(您没有遵循这一基本原则)。

答案 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)

我认为你真的想问“我怎样才能返回在我的函数中创建的对象?”有几种有效的方法:

  • 在堆上分配并返回指针
  • 使用自动变量并返回其值,而不是指针(编译器将复制它)
  • 让调用者通过指针或引用参数提供存储,并在那里构建对象。