C++ 为什么总是在堆栈上调用构造函数?

C++ 为什么总是在堆栈上调用构造函数?,c++,C++,出于某种原因,我决定在我的程序中永远不要使用动态内存分配。这意味着我的程序中的所有变量都是静态的,并且从不使用“new”构造函数。但以下代码崩溃,并产生堆栈溢出异常: VeryLargeObject x; // Global variable -> static memory void ResetTheObject() { x = VeryLargeObject(); } 显然,我要做的就是给x一个VeryLargeObject的默认值,它是一个包含许多不同变量的结构,它们

出于某种原因,我决定在我的程序中永远不要使用动态内存分配。这意味着我的程序中的所有变量都是静态的,并且从不使用“new”构造函数。但以下代码崩溃,并产生堆栈溢出异常:

VeryLargeObject x; // Global variable -> static memory 

void ResetTheObject() 
{
   x = VeryLargeObject(); 
}
显然,我要做的就是给x一个VeryLargeObject的默认值,它是一个包含许多不同变量的结构,它们自己的构造函数具有不同的复杂性(因此有相当多的初始化工作要做)。但是在这里,语言/编译器决定在复制之前应该在堆栈上执行此操作,并且由于VeryLargeObject对于堆栈来说太大,因此我的程序崩溃

然而,我找到了这个问题的解决方案:

VeryLargeObject x; 

void ResetTheObject() 
{
   new (&x) VeryLargeObject();  
}
我以前从未听说过这个,但它正是我想要的。这是一个“新的安置”。它在指针提供的已分配(或只是静态)内存上调用构造函数


既然我有了解决方案,我的问题就是:为什么这不是第一个代码的默认行为?如果没有一种不那么老套的方法来做这件事(即没有“新”这个词),那为什么呢?还有,为什么它会将指针发回给我,即使我只是提供了它?我认为C++是一门很棒的语言,但这看起来有点丑陋,而且没有很好的思考。p> 首先,启用优化可能会让您获得第一种语法所需的功能。如果没有它,以下是您要求编译器执行的操作:

  • 创建类型为
    VeryLargeObject
    的临时对象
  • 将其分配到名为
    x
    的全局变量中
  • 由于临时对象需要存储,编译器在堆栈上分配它们。实际上,编译器正在做的就是您要求编译器做的事情

    如果启用了优化,编译器可能会理解序列是什么,并保存副本。这要求编译器能够向自己证明,
    x
    的旧值不会以任何方式妨碍编译。既然您承认初始化相当复杂,那么如果编译器没有做到这一点,您可以原谅它

    你有两个选择。您可以创建一个就地初始化函数并调用它而不是构造函数,也可以像以前一样使用placement new


    使用“新位置”(placement new)的危险在于,它会替换
    x
    的旧值,而不会对其进行适当的破坏。它只是假设
    x
    未初始化。如果你可以用,那就用吧。编译器不允许假设,

    “由于某种原因,我决定在程序中永远不使用动态内存分配”。“我认为C++是一种很好的语言,但是这看起来有点丑陋,而且没有很好的考虑。”你看不到连接是否是BTW?“这意味着我的程序中的所有变量都是静态的”,不是。这并不意味着。你真的不想要一堆全局变量。你不能用这种方式使用新的布局。您首先需要通过调用原始对象的析构函数来销毁它。
    VeryLargeObject
    是否遵循5的规则?它有一个移动构造函数和一个移动赋值操作符吗?“我认为C++是一种很棒的语言,但是这看起来有点丑陋,而且没有很好的考虑。”我觉得奇怪的是,这个特殊的东西是C++中难看的东西。如果代码> x>代码>是POD,那就行了。最安全的方法是在执行新的放置之前只调用旧实例上的析构函数。如果是吊舱,无论如何,析构函数可能是一个空操作。如果不是,你会很高兴你叫它。我想太优化可能会有帮助,但我从O2切换到O4,它是一样的。事实上,VeryLargeObject有大量的对象需要初始化,而编译器只是懒得检查优化过程中是否有任何障碍。