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

问题描述 投票:5回答:7

示例:

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”。很简单。现在,如果我们运行它,我们将得到:

解除分配Buff:你好!浅黄色:¯ø_ˇ

显然是堆栈对象在这里不起作用-很明显,当函数退出时,指针_obj2指向堆栈中的某个位置。这就是为什么我在上一个问题中使用堆对象的原因,人们告诉我这是“愚蠢的”。

所以,第一个问题是:如果我如何将堆栈对象(obj2)转换为堆对象,以便在create()退出后不释放它?我想要一个直接的答案,而不是自大的“你” “做错了”。因为在这种情况下堆栈对象无法工作,所以堆对象似乎是唯一的方法。编辑:另外,转换回堆栈对象也将很有用。

[第二个问题:堆对象“错误”的具体示例是使用vector<string>*运算符创建新的new如果动态分配STL对象是错误的,那正确的方法是什么?显然,如果将它们创建为堆栈对象,则会失败,因为它们会立即被重新分配,但是我被告知(同样,非常高的等级)成员)动态分配它们可能会破坏堆。那么正确的方法是什么?

c++ stack heap
7个回答
9
投票

所以,第一个问题是:如果我如何将堆栈对象(obj2)转换为堆对象,以便在create()退出后不释放该对象?我想要一个直接的答案,

直接的答案是:您不能在堆栈和堆之间“转换”对象。您可以创建该对象的副本,该副本位于其他空间,正如其他人指出的那样,仅此而已。 。

[第二个问题:堆对象“错误”的具体示例是使用new运算符创建新的vector *。如果动态分配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);
}

如您所见,您仍然在堆栈上分配了所有内容,并且避免了依赖于复制构造函数返回对象副本的(有时是必然的)开销。


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运算符创建新的vector *。如果动态分配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. 查找关注点分离是什么(您未遵循此基本原理)。>>

1
投票

您必须复制构造新的堆对象(Class * foo = new Class(obj2))或将堆栈对象分配给堆对象(*obj1 = obj2)。


0
投票

唯一的方法是复制对象。


0
投票

获取堆栈变量的地址不会神奇地将其传输到堆中。您需要为您的类编写一个适当的复制构造函数,并使用_obj2 = new Class(obj2);


0
投票

您的堆栈对象将在create函数内部创建,并在超出函数范围后立即释放。指针无效。


0
投票

[我认为您实际上是在尝试问“如何返回在函数内部创建的对象?”有几种有效的方法:

© www.soinside.com 2019 - 2024. All rights reserved.