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

Jus*_*kva 5 c++ heap stack

例:

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;
}
Run Code Online (Sandbox Code Playgroud)

这将创建2个对象,创建指向它们的指针,然后main()调用每个对象的方法.Class对象创建一个char*并存储C字符串"Hello!" 在里面; ~Class()解除分配器释放内存.doSomething()方法使用printf()打印出"buff:%​​s".很简单.现在,如果我们运行它,我们得到这个:

Dealloc
Buff:你好!
Buff:¯ø_

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

所以,第一个问题是:如果我如何将堆栈对象(obj2)转换为堆对象,那么在create()退出后它不会被释放?我想要一个直接的答案,而不是像许多人那样傲慢的"你做错了".因为在这种情况下堆栈对象无法工作,所以堆对象似乎是唯一的方法.编辑:此外,转换回堆栈对象也是有用的.

第二个问题:堆对象"错误"的具体示例是vector<string>*使用new运算符创建新对象.如果动态分配STL对象是错误的,那么正确的方法是什么?显然,如果你将它们创建为堆栈对象,它会失败,因为它们会被立即释放,但我被告知(再次由一个非常高级别的成员),动态分配它们会破坏堆.那么正确的方法是什么?

Ben*_*n M 9

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

直接的答案是:您无法在堆栈和堆之间"转换"对象.你可以创建一个生活在另一个空间中的对象的副本,正如其他人指出的那样,但就是这样.

第二个问题:堆对象"错误"的具体示例是使用new运算符创建新的向量*.如果动态分配STL对象是错误的,那么正确的方法是什么?显然,如果你将它们创建为堆栈对象,它会失败,因为它们会被立即释放,但我被告知(再次由一个非常高级别的成员),动态分配它们会破坏堆.

动态分配STL对象本身不会破坏堆.(不知道你可能听说过那个.)

如果要在创建它的函数之外使用堆栈分配的STL对象,则不能,因为对象所在的堆栈空间仅在创建它的函数内有效.

但是,您可以返回该对象的副本:

std::vector<char> SomeFunc()
{
    std::vector<char> myvector;
    // myvector.operations ...
    return myvector;
}
Run Code Online (Sandbox Code Playgroud)

正如我所说的,这将返回对象的副本,而不是原始对象本身 - 这是不可能的,因为包含该对象的堆栈在函数返回后展开.

另一个选项是让调用者传入一个引用/指针指向函数操作的对象,如果这对您的特定场景有意义:

void SomeFunc(std::vector<char>& destination)
{
    // destination.operations ...
}

void AnotherFunc()
{
    std::vector<char> myvector;
    SomeFunc(myvector);
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,您仍然在堆栈中分配了所有内容,并且避免了依赖于复制构造函数返回对象副本的(有时是相应的)开销.

  • 返回一个对象的副本比这个答案要便宜得多,因为编译器几乎总能忽略副本. (3认同)

Mar*_*ork 5

所以,第一个问题是:如何将堆栈对象(obj2)转换为堆对象,以便在 create() 退出后它不会被释放?

这行:

_obj2 = &obj2;
Run Code Online (Sandbox Code Playgroud)

改成:

_obj2 = new Class(obj2);  // Create an object on the heap invoking the copy constructor.
Run Code Online (Sandbox Code Playgroud)

我想要一个直接的答案,而不是像很多人那样傲慢地回答“你做错了”。

这是您能得到的最直接的答案。显然你是 C++ 新手,所以我确信这不会按预期工作,因为你可能在类“Class”的定义中犯了一些错误(顺便说一句,名字很糟糕)。

此外,转换回堆栈对象也很有用。

class obj3(*_obj2);  // dereference the heap object pass it to the copy constructor.
Run Code Online (Sandbox Code Playgroud)

第二个问题:堆对象“错误”的具体示例是使用 new 运算符创建一个新的 vector<string>* 。如果动态分配STL对象是错误的,那么正确的方法是什么?

为什么要动态分配向量。只需在本地创建它即可。

std::vector<std::string> funct()
{
    std::vector<std::string>   vecString;
    // fill your vector here.

    return vecString;  // Notice no dynamic allocation with new,
}
Run Code Online (Sandbox Code Playgroud)

使用new/delete就是像C一样使用C++。你需要阅读的是智能指针。这些对象控制对象的生命周期,并在超出范围时自动删除对象。

std::auto_ptr<Class>   x(new Class);
Run Code Online (Sandbox Code Playgroud)

这里 x 是一个智能指针(类型为 auto_ptr),当它超出范围时,对象将被删除。但是您可以将 auto_ptr 返回给调用函数,它将安全地从函数中转移出来。它实际上比这复杂得多,你需要一本书。

显然,如果您将它们创建为堆栈对象,则会失败,因为它们会立即被释放,

当它超出范围时,它就会被取消分配。

但我被告知(再次,由一位非常高级的成员)动态分配它们可能会损坏堆。

如果你做错了。鉴于你的知识,这很有可能。但由于您没有提供类的定义,因此很难验证。

那么正确的做法是什么呢?

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