【问题标题】:Using malloc instead of new, and calling the copy constructor when the object is created使用 malloc 代替 new,并在创建对象时调用复制构造函数
【发布时间】:2011-02-10 11:03:16
【问题描述】:

我想试用 TBB 的可扩展分配器,但是当我不得不替换我的一些代码时感到困惑。 这是使用分配器完成分配的方式:

SomeClass* s = scalable_allocator<SomeClass>().allocate( sizeof(SomeClass) );

编辑:上面显示的并不是使用可扩展分配器完成分配的方式。作为ymett correctly mentioned,分配是这样完成的:

int numberOfObjectsToAllocateFor = 1;
SomeClass* s = scalable_allocator<SomeClass>().allocate( numberOfObjectsToAllocateFor );
scalable_allocator<SomeClass>().construct( s, SomeClass());
scalable_allocator<SomeClass>().destroy(s);
scalable_allocator<SomeClass>().deallocate(s, numberOfObjectsToAllocateFor);

这很像使用 malloc:

SomeClass* s = (SomeClass*) malloc (sizeof(SomeClass));

这是我要替换的代码:

SomeClass* SomeClass::Clone() const
{
   return new SomeClass(*this);
}//Clone

于是尝试了一个程序:

#include<iostream>
#include<cstdlib>
using namespace std;

class S
{
        public:
        int i;
        S() {cout<<"constructed"<<endl;}
        ~S() {cout<<"destructed"<<endl;}
        S(const S& s):i(s.i) {}
};

int main()
{
        S* s = (S*) malloc(sizeof(S));
        s = (S*) S();//this is obviously wrong
        free(s);
}

在这里我发现调用 malloc 并不会实例化对象(我之前从未使用过 malloc)。因此,在弄清楚如何将 *this 传递给复制 ctor 之前,我想知道在使用 malloc 时如何实例化对象。

【问题讨论】:

  • 为什么不覆盖operator new 为您感兴趣的课程或只是全局课程?
  • @sharptooth:这是个好主意,但现在,我只是在测试scalable_allocator 是否真的有助于避免堆争用。如果测试成功,覆盖 new 肯定会派上用场。谢谢:)
  • 如果分配器符合标准,它应该有构造和销毁方法:cplusplus.com/reference/std/memory/allocator/construct
  • 覆盖operator new() 更快、更可靠——你只需这样做并重新编译,看看它是否有帮助,你不需要更改调用代码——它会立即在任何地方生效。

标签: c++ memory-management malloc new-operator tbb


【解决方案1】:

malloc 获取原始内存后,您需要使用placement new

void* mem = malloc(sizeof(S));
S* s = new (mem) S(); //this is the so called "placement new"

当你处理完对象后,你必须确保显式调用它的析构函数。

s->~S();
free(mem);

【讨论】:

  • 谢谢。当使用 TBB 的可扩展分配器的全部目的是替换 new 时,使用“new”似乎违反直觉。但我想这是不同的,因为它正在使用新的位置。
【解决方案2】:

使用placement new

#include <memory>
//...
int main()
{
        S* s = (S*) malloc(sizeof(S));
        s = new (s) S();//placement new
        //...
        s->~S();
        free(s);
}

【讨论】:

    【解决方案3】:

    allocate() 的参数是对象的数量,而不是字节大小。 然后调用分配器的construct() 函数来构造对象。

    scalable_allocator<SomeClass> sa;
    SomeClass* s = sa.allocate(1);
    sa.construct(s, SomeClass());
    // ...
    sa.destroy(s);
    sa.deallocate(s);
    

    如果想将它与标准库容器或其他可识别 std 分配器的类型一起使用,只需为其指定分配器类型即可。

    std::vector<SomeClass, scalable_allocator<SomeClass>> v;
    

    【讨论】:

    • 我不同意。构造()用于放置新功能。我从 TBB 中提供的示例之一中获取了 allocate() 的语法。但是自从你发布了这个,我很感兴趣。我会检查并回复你。谢谢:)
    • 天哪!你说得对!非常感谢您纠正我!很遗憾,该网站无法多次投票给答案。我会投票一百次!一个问题:在 sa.construct(s, SomeClass()); ,是否创建了 SomeClass() 的临时对象?另外,我不明白分配 n 个对象的意义。如果我做了 sa.allocate(2);那么我是否必须使用 sa.construct(s, SomeClass()); 构造​​两个对象? ? ps:你能编辑一下你的答案吗?所以不允许我投票赞成你的答案,说你需要编辑它。
    • 编辑了我的问题以包含代码的更正版本。太感谢了!我的程序的输出现在是constructed destructed destructed。第一个“破坏”发生在construct() 函数之后/期间。想知道为什么。
    猜你喜欢
    • 2017-01-28
    • 2019-07-25
    • 1970-01-01
    • 2023-03-21
    • 2012-07-09
    • 1970-01-01
    • 2018-11-23
    • 1970-01-01
    • 2013-09-24
    相关资源
    最近更新 更多