【问题标题】:Instantiate a class on stack, where var is defined in header在堆栈上实例化一个类,其中 var 在 header 中定义
【发布时间】:2012-01-23 18:02:09
【问题描述】:

我目前正在尝试编写正确的 C++ 代码(运行它对于一些小型原型来说是可以的,但它很难看)。

我最近意识到堆和堆栈实例化的区别(O m = new O() vs. O m())。

现在我有一个类,其中头文件定义了一个变量,该变量包含一个表定义。

ChunkLoader.hpp:

TablePartion *tablePartial_;

ChunkLoader.cpp:

ChunkLoader() { tablePartial_ = new TablePartial(true, 0, 1); }

现在我想在堆栈上实例化 tablePartial,但我不能使用: TablePartial tablePartial_(true, 0, 1);

我完全失明了?如何在堆栈上分配 tablePartial_? 或者我完全错了,我不能在构造函数中使用,因为它会在构造函数之后超出范围并因此被释放?但由于我读到堆栈变量在性能方面更好,所以我想使用堆栈实例化(并且得到delete 的红色)。

主要原因:堆栈溢出告诉我尽可能摆脱指针。 :)

【问题讨论】:

  • 你能澄清一下你在堆栈上的意思吗?你的意思是一个局部变量,还是你在谈论将构造函数初始化器传递给父类?我有点困惑。
  • tablePartial_ChunkLoader 类的成员,还是函数中的简单变量,还是全局变量?
  • 注意,O m(); 与变量无关;这是一个函数声明。
  • 编辑了我的帖子以澄清。现在,tablePartial_ 是一个指向 TablePointer 实例的指针。我想要实现的是,ChunkLoader 在堆栈上持续存在tablePartial_。 @MooingDuck 是的,tablePartial_ 是 ChunkLoader 的私有成员。 @FredOverflow 我的意思是实例化一个 O 类并调用变量 m (假设构造函数接受一个布尔值,所以它将是 O m(true) 例如)。
  • @Bouncner:哦,如果tablePartial_ 是一个指针,它完全 会改变一切,并使所有现有答案无效。短篇小说要么使TablePartion 成为成员本身(无指针),要么将其保留在堆上。成员指针几乎不应该指向堆栈上的某个东西。

标签: c++ heap-memory instantiation stack-memory


【解决方案1】:

首先,您可能应该避免使用“堆栈上”或“堆上”这些术语,它们是与所讨论的概念无关的实现细节。相反,我们讨论对象的生命周期,根据automatic(或多或少与堆栈相关)、dynamic(或多或少与堆相关)、static(或多或少相关带有全局变量)和thread(这是一个特定于线程的全局变量)。

在回答您的具体问题时,您可以使用构造函数初始化器来初始化您的变量:

ChunkLoader() 
   : tablePartial_(true, 0, 1) 
{ 
}

【讨论】:

  • 虽然我不同意第一段,但我赞成正确的解决方案。
  • shrug 虽然只有第一句话是我的(后面会添加更多),但这是一个有效的观点。有些系统没有堆栈但可以很好地运行 C++ 代码。我什至为这样的系统(无堆栈虚拟机)编写了 C-ish 编译器。
  • 这实际上是错误的。如果你这样做ChunkLoader* p = new ChunkLoaderp 将在堆上,tablePartial_ 也将在堆上。
  • @LuchianGrigore,你也不是你自己的定义。相反,我会争辩说你是为了它而吹毛求疵,他显然是指“假设类本身是在'堆栈'上实例化的”。
  • @Blindy 我刚刚编辑了我的答案。另外,我不是为了它而吹毛求疵。说使用初始化列表会将类放入自动存储中是错误的。而且,它不会改变你没有回答问题的事实。
【解决方案2】:

因为类声明是:

class MyClass
{
   SomeOtherClass x;
};

x 完全包含在MyClass 中(它不是指向SomeOtherClass 的指针)。

所以,在栈上创建对象MyClass时,x也会在栈上,而在堆上创建对象MyClass时,x也会在堆上。

编辑:

据我了解,您想在堆栈上分配x。为此,MyClass 的任何实例也必须在堆栈上。为此,您可以将new 运算符设为private:

class MyClass
{
   SomeOtherClass x;
private:
   void* operator new(size_t);
};

【讨论】:

  • 这并不是我真正的答案,但它澄清了我问题中的一个重要误解。 ChunkLoader 可能会保存相当大的数据量(数十到数百兆字节)。据我所知,这不符合堆栈实例化的条件。当我理解正确时,所有类变量都将在堆上,而拥有的对象也在堆上。由于 ChunkLoader 将在堆上,我不必关心 tablePartial_。对吗?
  • @Bouncner:tablePartial_ 是成员,ChunkLoader 也是如此。它实际上是ChunkLoader 的一部分。就像你的胃是你的一部分。你不应该担心它在哪里。
【解决方案3】:

如果您没有在 C++ 中使用“new”一词(避免此对话的 malloc 和其他 C/OS 调用),那么您还没有在“堆”上动态分配内存。

如果不使用 new ,您在 main() 中创建的所有内容以及其中调用的函数都会进入堆栈。当你输入一个新的函数调用时,你会得到一个新的栈帧,并且所有的变量都是这样声明的:

void foo() {
    int x;
    std::string y;
}

在堆栈上创建。

您甚至可以获取指向基于堆栈的对象的“指针”,这样您就可以像使用指向堆对象的指针一样多态地使用它:

//These should be "classes" with private/public hiding but I'm being lazy.
struct MyClass {
    int x;
    virtual void foo();
};

//These should be "classes" with private/public hiding but I'm being lazy.
struct MyClassDerived : MyClass {
    void foo() { std::cerr << "foo called!" << std::endl; }
};

int main() {
    MyClassDerived x;
    MyClass* = &x;
    x->foo();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2012-04-23
    • 1970-01-01
    • 2019-03-12
    相关资源
    最近更新 更多