【问题标题】:Stack and heap allocations of instantiated objects C++堆叠和堆分配实例化对象C ++
【发布时间】:2016-09-02 05:55:35
【问题描述】:

我有 C 方面的背景,并试图了解 C++ 类以及在对象离开范围时如何调用析构函数。作为旁注,鉴于我正在尝试做的事情的性质,我宁愿不使用像 std::array 或 std::vector 这样的 STL 结构作为我在下面展示的数据容器。

这是我理解的高级概述。给定一些类:

class some_class{
    public:
        int * member;
        size_t n_members;

        some_class(size_t count) ...
        ~some_class() ...

        // a member function or operator overload
        // that returns an instance of some_class
        some_class do_something()
}

...

some_class * container;
// Some scope
{
    some_class foo = some_class();
    some_class * bar = new some_class();
    container[0] = bar;
}

some_class foo 离开作用域时,它的析构函数被调用。如果我想将指向some_class 实例的指针存储到作用域之外的container 中,我需要在堆上实例化some_class bar,以便在离开作用域时不会立即释放内存 - 就像我一样会在 C 中。

现在,some_class 的目的是保存任意大量的数据,因此 int * member 需要在堆上分配。

如上所示,some_class() 的构造函数和析构函数如下所示:

// some_class constructor
some_class::some_class(size_t count) : n_members(count){
    member = new int[count];
}

// some_class destructor
some_class::~some_class(){
    delete[] member;
}

现在我的问题变得明显了:如果我需要添加从do_something() 方法返回的some_class 的实例,我肯定会出现内存错误(在这种情况下,是双释放),因为do_something()返回堆栈分配的some_class

some_class * container = new some_class[n];
// Some scope
{
    some_class foo = some_class();
    some_class bar = foo.do_something();
    container[0] = &bar; // <-- I know this is stupid but that's the point of this question
}
delete[] container;

我的解决方法是让foo.do_something() 返回一个指向some_class 实例的指针。当然,不是解决办法。如何以真正的 C++ 方式正确解决这种情况?

例如,我一直在阅读的一件事是使用共享指针或唯一指针(或一般的智能指针)。但是,我的理解是,使用这些指针需要您在堆中实例化您的对象。对于要求 foo.do_something() 返回指针的整个问题也确实无济于事。

无论如何,任何想法都将不胜感激。

【问题讨论】:

  • 如果我需要添加从 do_something() 方法返回的 some_class 的实例,我保证会出现内存错误 是的。请参阅The Rule of Three 来解决这个问题。
  • As a side note, given the nature of what I am trying to do, I would rather not use STL structures 为什么。鉴于您不是 C++ 专家,您可能存在一些我们可以纠正的误解。
  • @LokiAstari - 简而言之:我试图保持对将被此类结构抽象掉的数据访问模式的控制。如果我正在构建某种应用程序,我会说去做,因为它很容易。但对我来说,了解它的工作原理比如何使用它更重要。
  • @FrancoSolleza:这两种结构都归结为简单地使用指针来访问内存块(一个堆栈一个动态)。它们是指针周围的非常薄的包装器。您可以完全控制何时分配内存,以便这些结构可以解决您的问题。

标签: c++ pointers c++11 memory-management


【解决方案1】:

智能指针可用于在 some_class 中保存指针,如下所示:

#include <memory>

class some_class{
  public:
    // smart pointer instead of raw pointer
    std::unique_ptr<int[]> member;
    size_t n_members;

    some_class(size_t count = 0) : member(new int[count]), n_members(count) {}

    // destructor not needed

    // a member function or operator overload
    // that returns an instance of some_class
    some_class do_something();
};

int main()
{
  int n = 3;
  // smart pointer instead of raw pointer
  std::unique_ptr<some_class[]> container(new some_class[n]);
  {
    some_class foo = some_class(10);
    some_class bar = foo.do_something();
    // use std::move to transfer pointer ownership
    container[0] = std::move(bar);
  }
  // no need to delete
}

【讨论】:

    【解决方案2】:

    我曾经精通 C++,但很久以前就转向 Java,现在我的 C++ 已经生疏了 :(.

    您可以做的一件事是创建一个接受类成员的构造函数。在其中,只需将属性复制到您的新实例。 (也可以使用静态方法而不是重载构造函数来实现)。

    some_class::some_class(some_class* obj){
        member = obj->member;
        n_members = obj->n_members;
    }
    

    所以你可以在你的代码中这样做:

    some_class * container;
    // Some scope
    {
        some_class foo = some_class();
        some_class * bar = new some_class();
        container = new some_class(bar);
    }
    

    希望它对你有用。

    【讨论】:

    • 是的,你的 C++ 已经很生锈了。如果您在复制构造函数中所做的只是成员方式的复制,那么您根本没有帮助这种情况,因为这正是编译器将自动生成的复制构造函数,并且对于像这样的类它不会正常工作.此外,它需要通过引用获取对象,因为通过值获取对象需要复制构造函数。
    • 和SP、BP一起玩怎么样?它会解决问题,但我不确定 C++ 的效果如何。
    • 是的,我忘记了 * 和 ->,->。但结果是,你的反对票将使我最后一次尝试回答 C++ 问题。
    猜你喜欢
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 2018-04-02
    • 2012-07-11
    • 2020-08-24
    相关资源
    最近更新 更多