C ++,是不是可以直接调用构造函数,而不需要new?

Posted

技术标签:

【中文标题】C ++,是不是可以直接调用构造函数,而不需要new?【英文标题】:C++, is it possible to call a constructor directly, without new?C ++,是否可以直接调用构造函数,而不需要new? 【发布时间】:2011-01-30 11:16:50 【问题描述】:

如果我已经有对象的内存,我可以显式调用构造函数而不使用new吗?

class Object1
    char *str;
public:
    Object1(char*str1)
        str=strdup(str1);
        puts("ctor");
        puts(str);
    
    ~Object1()
        puts("dtor");
        puts(str);
        free(str);
    
;

Object1 ooo[2] = 
     Object1("I'm the first object"), Object1("I'm the 2nd")
;

do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
ooo[0].Object1("I'm the 3rd object in place of first"); // ???? - reuse memory

【问题讨论】:

哦,是的,这看起来很有趣。我会回答这是不可能的,但我最好等一下再出丑。我很喜欢这个。 简短的回答是不,长的回答是有一种方法可以实现内存重用,它被称为放置新。但是保持这个位置 new 除了重用内存之外还有其他用途。 您是否有理由不创建赋值运算符? @Dennis Zickefoose,是的。删除和重建方法不同 所以从赋值运算符中调用这些方法。这是处理分配的正确方法。 【参考方案1】:

有点。您可以使用placement new 使用已分配的内存运行构造函数:

 #include <new>

 Object1 ooo[2] = Object1("I'm the first object"), Object1("I'm the 2nd");
 do_smth_useful(ooo);
 ooo[0].~Object1(); // call destructor

 new (&ooo[0]) Object1("I'm the 3rd object in place of first");

所以,您仍在使用 new 关键字,但没有进行内存分配。

【讨论】:

是的,直接析构函数调用实际上是必要的,以允许对象释放任何资源,然后用新构造的对象覆盖对象。 +1 - 虽然严格来说,“安置新”并不完全是“没有新”;-) @Steve314:我知道,这就是为什么我指出关键字仍然存在,但没有进行分配。 顶部不应该有很大的“是”,这是误导 另外,请注意,如果构造函数抛出,灾难将会发生。该对象将保持未初始化状态,但析构函数仍会在将来的某个时间点被调用。【参考方案2】:

我认为您正在寻找新的展示位置。 C++ FAQ Lite 很好地总结了你是如何做到这一点的。这篇文章有几个重要的陷阱:

    您应该 #include &lt;new&gt; 使用放置新语法。 您的内存缓冲区需要针对您正在创建的对象正确对齐。 手动调用析构函数是您的工作。

【讨论】:

你必须#include 一个库才能使用一些 C++ 语法?我不是在反驳你——我只是觉得这真的很奇怪。 @Steve314:C++ 语法为new 提供参数,这些参数被传递给operator new 的匹配重载。您需要该库来提供所需的重载,operator new(size_t,void*) 我不知道需要调用operator new - 我已经分配了内存,我认为放置 new 只是调用构造函数。虽然(1)我可能在某个地方包含了&lt;new&gt;,并且(2)我的编译器总是有可能让我摆脱了一些顽皮的事情,但我当然一直没有担心这一点。我想是时候回顾一下了,看看我是否做错了什么。 它调用在标准库中为您定义的替换运算符 new,它不分配任何内存,它只是返回您传递给它的内存。然后像往常一样调用构造函数,从而实现您想要的。这不是真正的语法,它是一个重新定义的运算符 new 基本上只是返回它的额外参数【参考方案3】:

让我向您展示一些关于如何完成它的代码,包括构造和破坏

#include <new>

// Let's create some memory where we will construct the object.
MyObject* obj = (MyObject*)malloc(sizeof(MyObject));

// Let's construct the object using the placement new
new(obj) MyObject();

// Let's destruct it now
obj->~MyObject();

// Let's release the memory we used before
free(obj);
obj = 0;

我希望上面的总结能让事情更清楚。

【讨论】:

【参考方案4】:

从字面上看,不,没有“new”关键字你就做不到。查看所有关于placement new的答案,了解如何使用“new”关键字调用构造函数而不实际分配内存。

【讨论】:

有人知道定义这个的规范的相关部分吗? @nmr:您的意思是显示placement new 确实做到了的部分,还是显示构造函数不能以其他方式显式调用的部分方式。 后者——不能直接调用构造函数。 @JaveneCPPMcGowan:图书馆使用新的展示位置。只有编译器本身可以调用构造函数而不需要放置 new。 @Ben Voigt 我发表评论是因为我明白我需要包含 new 才能使用 Placement new。我想验证一下,您不需要包含 new 即可使用该语法。但是,很遗憾我们必须使用我从未听说过的语法,而不是 obj.std::string() 例如。我不明白为什么 ctor 没有名字,为什么 c++ 必须如此复杂和充满语法。【参考方案5】:

是的,当您拥有自己分配的缓冲区时,您会使用placement new。 Brian Bondy 在一个相关问题中给出了很好的回答:

What uses are there for "placement new"?

【讨论】:

【参考方案6】:

你可以调用析构函数,但是不会回收内存,你的调用就相当于函数调用。您必须记住,在析构函数下面做了两件事:根据您的规范破坏对象,并回收内存。由于无论如何都会为分配在堆栈上的对象调用 dtor,因此调用它两次可能会导致未定义的行为。

【讨论】:

相反,如果Object1 持有指向需要为deleted 的事物的指针,则显式析构函数调用将确保在用新构造的对象覆盖对象之前发生这种情况。然后自动堆栈析构函数调用将销毁新构造的对象,因此您不会在同一个对象上调用它两次。 但在我的示例代码中,我在初始化程序中创建了 2 个 Object1,然后破坏第一个并重新创建(重建)以代替第一个和第三个对象。当这个块关闭时,ooo[2] 将调用两个析构函数。那么这个样本是正常的吗?析构函数是自行回收内存,还是仅在堆栈收缩时与 delete 或隐式“delete”一起使用? 析构函数不会回收被销毁对象的内存,但它确实可以在对象拥有的额外内存上调用 delete(或 delete[],或 free,或 HeapFree 等)。当析构函数运行时,相关的内存将被回收。【参考方案7】:

是的,使用placement new - 如上所述,但您可能会考虑使用第二个工厂类来管理存储,即使这意味着复制对象。 memcpy() 对于小对象来说通常很便宜。

【讨论】:

我真的可以为对象做一个 memcpy 吗?我想写一个相当通用的容器,比如 STL 向量。一些对象可以依赖于它的地址(存储在自身地址中)【参考方案8】:

您可以使用以下模板

template <typename T, typename... Args>
inline void InitClass(T &t, Args... args)

    t.~T();
    new (&t) T(args...);

用法:

struct A

   A() 
   A(int i) : a(i) 
   int a;
 my_value;

InitClass(my_value);
InitClass(my_value, 5);

【讨论】:

【参考方案9】:

基于 cmets,这仅适用于 Microsoft C++ 编译器

很简单,没有new:

    imguistate = (int *)malloc(ImGui::GetInternalStateSize());
    memset(imguistate, 0, ImGui::GetInternalStateSize());
    ((ImGuiState *)imguistate)->ImGuiState::ImGuiState();

这适用于任何类:

class SomeClass 
public:
    SomeClass() 
        printf("Called constructor\n");
    
;

int main () 
    SomeClass *someclass = new SomeClass;
    someclass->SomeClass::SomeClass(); // call constructor again

【讨论】:

什么是 ImGuiState::ImGuiState()?这适用于任何课程吗? 是的,它适用于任何类,自定义类的扩展答案。 不,它在 C++ 中不起作用(请阅读问题标题的第一个单词,并用所有标点符号解析它)。 gcc (g++) 说“error: cannot call constructor 'SomeClass::SomeClass' directly”。 clang++ 说“error: cannot refer to type member 'SomeClass' in 'SomeClass' with '-&gt;'”。你的编译器有什么问题,是微软的 ManagedC++ 吗?它是否有任何标准或类似于标准合规性的东西? @osgx 我正在使用 Microsoft Visual Studio 2015 社区版(非托管 C++)。感谢您的信息,不知道它在 gcc/clang 中不起作用。 似乎没有记录:msdn.microsoft.com/en-us/library/hh567368.aspx / msdn.microsoft.com/en-us/library/34h23df8.aspx。尝试/Za/Ze/Zc 选项

以上是关于C ++,是不是可以直接调用构造函数,而不需要new?的主要内容,如果未能解决你的问题,请参考以下文章

复制构造函数与赋值运算符(=)有何不同

C语言编写精确到毫秒的时间函数

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

构造函数 析构函数 拷贝构造函数 ~~~~~~~~~~构造函数

C#-面向对象——如何调用使用类 普通方法静态方法的使用

C和C++是不是都可以函数嵌套调用,但是不能函数嵌套定义?