过去几天我一直在研究这个问题,到目前为止,除了教条论点或诉诸传统(即“这是 C++ 方式!”)之外,我还没有真正找到任何令人信服的东西。
如果我正在创建一个对象数组,那么使用以下命令的令人信服的原因(除了易用性之外)是什么:
#define MY_ARRAY_SIZE 10
// ...
my_object * my_array=new my_object [MY_ARRAY_SIZE];
for (int i=0;i<MY_ARRAY_SIZE;++i) my_array[i]=my_object(i);
over
#define MEMORY_ERROR -1
#define MY_ARRAY_SIZE 10
// ...
my_object * my_array=(my_object *)malloc(sizeof(my_object)*MY_ARRAY_SIZE);
if (my_object==NULL) throw MEMORY_ERROR;
for (int i=0;i<MY_ARRAY_SIZE;++i) new (my_array+i) my_object (i);
据我所知,后者比前者更有效(因为您没有将内存初始化为某些非-随机值/不必要地调用默认构造函数),唯一的区别实际上是你清理的一个:
delete [] my_array;
和另一个你清理的:
for (int i=0;i<MY_ARRAY_SIZE;++i) my_array[i].~T();
free(my_array);
我出于一个令人信服的原因而退出。据我所知,它是 C++(而不是 C),因此不应该使用 malloc
和 free
的事实并非如此 - 令人信服的和它教条一样多。我是否遗漏了一些使 new []
优于 malloc
的东西?
我的意思是,据我所知,您甚至根本不能使用 new [] 来创建一个没有默认、无参数构造函数的数组,而因此可以使用malloc
方法。
I've been looking into this for the past few days, and so far I haven't really found anything convincing other than dogmatic arguments or appeals to tradition (i.e. "it's the C++ way!").
If I'm creating an array of objects, what is the compelling reason (other than ease) for using:
#define MY_ARRAY_SIZE 10
// ...
my_object * my_array=new my_object [MY_ARRAY_SIZE];
for (int i=0;i<MY_ARRAY_SIZE;++i) my_array[i]=my_object(i);
over
#define MEMORY_ERROR -1
#define MY_ARRAY_SIZE 10
// ...
my_object * my_array=(my_object *)malloc(sizeof(my_object)*MY_ARRAY_SIZE);
if (my_object==NULL) throw MEMORY_ERROR;
for (int i=0;i<MY_ARRAY_SIZE;++i) new (my_array+i) my_object (i);
As far as I can tell the latter is much more efficient than the former (since you don't initialize memory to some non-random value/call default constructors unnecessarily), and the only difference really is the fact that one you clean up with:
delete [] my_array;
and the other you clean up with:
for (int i=0;i<MY_ARRAY_SIZE;++i) my_array[i].~T();
free(my_array);
I'm out for a compelling reason. Appeals to the fact that it's C++ (not C) and therefore malloc
and free
shouldn't be used isn't -- as far as I can tell -- compelling as much as it is dogmatic. Is there something I'm missing that makes new []
superior to malloc
?
I mean, as best I can tell, you can't even use new []
-- at all -- to make an array of things that don't have a default, parameterless constructor, whereas the malloc
method can thusly be used.
发布评论
评论(11)
这取决于你如何定义“引人注目”。迄今为止您所拒绝的许多论点对于大多数 C++ 程序员来说肯定是有吸引力的,因为您的建议不是在 C++ 中分配裸数组的标准方法。
简单的事实是:是的,您绝对可以按照您描述的方式做事。您所描述的内容没有理由不起作用。
但话又说回来,你可以在 C 中使用虚函数。如果你投入时间和精力,你可以用纯 C 实现类和继承。这些也都是完全实用的。
因此,重要的不是某件事能否发挥作用。但更多的是关于成本是什么。在 C 中实现继承和虚函数比在 C++ 中更容易出错。在 C 中实现它的方法有多种,这会导致实现不兼容。然而,因为它们是 C++ 的一流语言功能,所以有人不太可能手动实现该语言提供的功能。这样,大家的继承和虚函数就可以配合C++的规则了。
这也是同样的道理。那么手动 malloc/free 数组管理的收益和损失是什么?
我不能说我接下来要说的任何内容对你来说都是“令人信服的理由”。我相当怀疑它会,因为你似乎已经下定决心了。但郑重声明:
性能
您声明如下:
这种说法表明效率增益主要在于所讨论对象的构造中。即调用了哪些构造函数。该语句假定您不想想要调用默认构造函数;您仅使用默认构造函数来创建数组,然后使用真正的初始化函数将实际数据放入对象中。
好吧...如果这不是您想要做的怎么办?如果您想要创建一个默认构造的空数组怎么办?在这种情况下,这种优势就完全消失了。
脆弱性
让我们假设数组中的每个对象都需要有一个专门的构造函数或对其进行调用的东西,这样初始化数组就需要这种东西。但请考虑您的销毁代码:
对于简单的情况,这很好。您有一个宏或 const 变量来表示您有多少个对象。然后循环遍历每个元素以销毁数据。这对于一个简单的例子来说非常好。
现在考虑一个真实的应用程序,而不是一个示例。您将在多少个不同的地方创建数组?几十个?数百个?每一个都需要有自己的 for 循环来初始化数组。每一个都需要有自己的 for 循环来销毁数组。
即使输入错误一次,您也可能会损坏内存。或者不删除某些东西。或者任何其他可怕的事情。
这里有一个重要的问题:对于给定的数组,你在哪里保存大小?您知道为创建的每个数组分配了多少项吗?每个数组可能都有自己的方式来知道它存储了多少项。因此每个析构函数循环都需要正确获取这些数据。如果弄错了……繁荣。
然后我们有异常安全,这是一个全新的蠕虫罐头。如果其中一个构造函数抛出异常,则需要销毁先前构造的对象。你的代码没有这样做;它不是异常安全的。
现在,考虑替代方案:
这不会失败。它总是会破坏每一个元素。它跟踪数组的大小,并且是异常安全的。所以它保证能够工作。它不可能不工作(只要你用
new[]
分配它)。当然,你可以说你可以将数组包装在一个对象中。这是有道理的。您甚至可以在数组的类型元素上模板化对象。这样,所有析构器代码都是相同的。大小包含在对象中。也许,只是也许,您意识到用户应该对内存分配的特定方式有一定的控制,这样它就不仅仅是
malloc/free
。恭喜:您刚刚重新发明了
std::vector
。这就是为什么许多 C++ 程序员甚至不再输入
new[]
的原因。灵活性
您的代码使用
malloc/free
。但假设我正在做一些分析。我意识到对于某些频繁创建的类型来说,malloc/free
的成本太高了。我为他们创建了一个特殊的内存管理器。但是如何将所有数组分配挂钩到它们呢?好吧,我必须在代码库中搜索创建/销毁这些类型的数组的任何位置。然后我必须相应地改变他们的内存分配器。然后我必须不断监视代码库,以便其他人不会更改这些分配器或引入使用不同分配器的新数组代码。
如果我使用
new[]/delete[]
,我可以使用运算符重载。我只是为这些类型的运算符new[]
和delete[]
提供重载。无需更改任何代码。对于某人来说,规避这些超载要困难得多;他们必须积极尝试。等等。因此,我获得了更大的灵活性和合理的保证,我的分配器将在应该使用的地方使用。
可读性
考虑一下:
与此比较:
客观地说,哪一个更容易阅读和理解正在发生的事情?
只需查看以下语句:
(my_object *)malloc(sizeof(my_object) * MY_ARRAY_SIZE)
。这是一个非常低级的事情。你没有分配任何东西的数组;你正在分配一大块内存。您必须手动计算内存块的大小,以匹配对象的大小*您想要的对象的数量。它甚至还有演员阵容。相比之下,
new my_object[10]
讲述了这个故事。new
是“创建类型实例”的 C++ 关键字。my_object[10]
是my_object
类型的 10 个元素数组。它简单、明显且直观。没有转换,没有字节大小的计算,什么都没有。malloc
方法需要学习如何惯用地使用malloc
。new
方法只需要了解new
的工作原理即可。发生的事情变得不那么冗长并且更加明显。此外,在
malloc
语句之后,您实际上并没有对象数组。malloc
只是返回一个内存块,您已告诉 C++ 编译器假装该内存块是指向对象的指针(带有强制转换)。它不是一个对象数组,因为C++中的对象有生命周期。对象的生命周期直到其被构造之后才开始。该内存中还没有调用过构造函数,因此其中没有活动对象。此时的
my_array
不是一个数组;它只是一个内存块。在您在下一步中构造它们之前,它不会成为my_object
的数组。对于新程序员来说,这非常不直观;需要经验丰富的 C++ 技术人员(可能是从 C 语言学习的人)才能知道这些不是活动对象,应该小心对待。该指针的行为尚未像正确的my_object*
那样,因为它尚未指向任何my_object
。相比之下,在
new[]
情况下确实有活动对象。对象已构建;它们是活的并且完全成形。您可以像使用任何其他my_object*
一样使用此指针。Fin
以上均未表明此机制在适当的情况下没有潜在用处。但承认某物在某些情况下的效用是一回事。说它应该是默认的做事方式是另一回事。
It depends on how you define "compelling". Many of the arguments you have thus far rejected are certainly compelling to most C++ programmers, as your suggestion is not the standard way to allocate naked arrays in C++.
The simple fact is this: yes, you absolutely can do things the way you describe. There is no reason that what you are describing will not function.
But then again, you can have virtual functions in C. You can implement classes and inheritance in plain C, if you put the time and effort into it. Those are entirely functional as well.
Therefore, what matters is not whether something can work. But more on what the costs are. It's much more error prone to implement inheritance and virtual functions in C than C++. There are multiple ways to implement it in C, which leads to incompatible implementations. Whereas, because they're first-class language features of C++, it's highly unlikely that someone would manually implement what the language offers. Thus, everyone's inheritance and virtual functions can cooperate with the rules of C++.
The same goes for this. So what are the gains and the losses from manual malloc/free array management?
I can't say that any of what I'm about to say constitutes a "compelling reason" for you. I rather doubt it will, since you seem to have made up your mind. But for the record:
Performance
You claim the following:
This statement suggests that the efficiency gain is primarily in the construction of the objects in question. That is, which constructors are called. The statement presupposes that you don't want to call the default constructor; that you use a default constructor just to create the array, then use the real initialization function to put the actual data into the object.
Well... what if that's not what you want to do? What if what you want to do is create an empty array, one that is default constructed? In this case, this advantage disappears entirely.
Fragility
Let's assume that each object in the array needs to have a specialized constructor or something called on it, such that initializing the array requires this sort of thing. But consider your destruction code:
For a simple case, this is fine. You have a macro or const variable that says how many objects you have. And you loop over each element to destroy the data. That's great for a simple example.
Now consider a real application, not an example. How many different places will you be creating an array in? Dozens? Hundreds? Each and every one will need to have its own
for
loop for initializing the array. Each and every one will need to have its ownfor
loop for destroying the array.Mis-type this even once, and you can corrupt memory. Or not delete something. Or any number of other horrible things.
And here's an important question: for a given array, where do you keep the size? Do you know how many items you allocated for every array that you create? Each array will probably have its own way of knowing how many items it stores. So each destructor loop will need to fetch this data properly. If it gets it wrong... boom.
And then we have exception safety, which is a whole new can of worms. If one of the constructors throws an exception, the previously constructed objects need to be destructed. Your code doesn't do that; it's not exception-safe.
Now, consider the alternative:
This can't fail. It will always destroy every element. It tracks the size of the array, and it's exception-safe. So it is guaranteed to work. It can't not work (as long as you allocated it with
new[]
).Of course, you could say that you could wrap the array in an object. That makes sense. You might even template the object on the type elements of the array. That way, all the desturctor code is the same. The size is contained in the object. And maybe, just maybe, you realize that the user should have some control over the particular way the memory is allocated, so that it's not just
malloc/free
.Congratulations: you just re-invented
std::vector
.Which is why many C++ programmers don't even type
new[]
anymore.Flexibility
Your code uses
malloc/free
. But let's say I'm doing some profiling. And I realize thatmalloc/free
for certain frequently created types is just too expensive. I create a special memory manager for them. But how to hook all of the array allocations to them?Well, I have to search the codebase for any location where you create/destroy arrays of these types. And then I have to change their memory allocators accordingly. And then I have to continuously watch the codebase so that someone else doesn't change those allocators back or introduce new array code that uses different allocators.
If I were instead using
new[]/delete[]
, I could use operator overloading. I simply provide an overload for operatorsnew[]
anddelete[]
for those types. No code has to change. It's much more difficult for someone to circumvent these overloads; they have to actively try to. And so forth.So I get greater flexibility and reasonable assurance that my allocators will be used where they should be used.
Readability
Consider this:
Compare it to this:
Objectively speaking, which one of these is easier to read and understand what's going on?
Just look at this statement:
(my_object *)malloc(sizeof(my_object) * MY_ARRAY_SIZE)
. This is a very low level thing. You're not allocating an array of anything; you're allocating a hunk of memory. You have to manually compute the size of the hunk of memory to match the size of the object * the number of objects you want. It even features a cast.By contrast,
new my_object[10]
tells the story.new
is the C++ keyword for "create instances of types".my_object[10]
is a 10 element array ofmy_object
type. It's simple, obvious, and intuitive. There's no casting, no computing of byte sizes, nothing.The
malloc
method requires learning how to usemalloc
idiomatically. Thenew
method requires just understanding hownew
works. It's much less verbose and much more obvious what's going on.Furthermore, after the
malloc
statement, you do not in fact have an array of objects.malloc
simply returns a block of memory that you have told the C++ compiler to pretend is a pointer to an object (with a cast). It isn't an array of objects, because objects in C++ have lifetimes. And an object's lifetime does not begin until it is constructed. Nothing in that memory has had a constructor called on it yet, and therefore there are no living objects in it.my_array
at that point is not an array; it's just a block of memory. It doesn't become an array ofmy_object
s until you construct them in the next step. This is incredibly unintuitive to a new programmer; it takes a seasoned C++ hand (one who probably learned from C) to know that those aren't live objects and should be treated with care. The pointer does not yet behave like a propermy_object*
, because it doesn't point to anymy_object
s yet.By contrast, you do have living objects in the
new[]
case. The objects have been constructed; they are live and fully-formed. You can use this pointer just like any othermy_object*
.Fin
None of the above says that this mechanism isn't potentially useful in the right circumstances. But it's one thing to acknowledge the utility of something in certain circumstances. It's quite another to say that it should be the default way of doing things.
如果您不想通过隐式构造函数调用来初始化内存,而只需要为
placement new
提供有保证的内存分配,那么使用malloc
和就完全没问题了。 >free
而不是new[]
和delete[]
。使用
new
而不是malloc
的令人信服原因是new
通过构造函数调用提供隐式初始化,从而节省额外的< code>memset 或相关函数调用会发布malloc
并且对于new
您不需要在每次分配后检查NULL
,只需包含异常处理程序即可完成工作,从而节省您多余的错误检查,这与malloc
。这两个令人信服的理由不适用于您的使用。
哪一种性能高效只能通过分析来确定,您现在的方法没有任何问题。顺便说一句,我也没有看到为什么使用
malloc
而不是new[]
的令人信服的理由。If you do not want to get your memory initialized by implicit constructor calls, and just need an assured memory allocation for
placement new
then it is perfectly fine to usemalloc
andfree
instead ofnew[]
anddelete[]
.The compelling reasons of using
new
overmalloc
is thatnew
provides implicit initialization through constructor calls, saving you additionalmemset
or related function calls post anmalloc
And that fornew
you do not need to check forNULL
after every allocation, just enclosing exception handlers will do the job saving you redundant error checking unlikemalloc
.These both compelling reasons do not apply to your usage.
which one is performance efficient can only be determined by profiling, there is nothing wrong in the approach you have now. On a side note I don't see a compelling reason as to why use
malloc
overnew[]
either.我不会说。
最好的方法是:
这是因为内部向量可能正在为您进行新的放置。它还管理您没有考虑到的与内存管理相关的所有其他问题。
I would say neither.
The best way to do it would be:
This is because internally vector is probably doing the placement new for you. It also managing all the other problems associated with memory management that you are not taking into account.
您在这里重新实现了
new[]
/delete[]
,并且您所编写的内容在开发专用分配器中非常常见。与分配相比,调用简单构造函数的开销将花费很少的时间。它不一定“更高效”——它取决于默认构造函数和
operator=
的复杂性。尚未提及的一件好事是,
new[]
/delete[]
可以知道数组的大小。delete[]
只是执行正确的操作并在被要求时销毁所有元素。拖动一个附加变量(或三个)以便您准确地了解如何销毁数组是一件痛苦的事情。然而,专用的集合类型将是一个不错的选择。为了方便起见,最好使用
new[]
/delete[]
。它们带来的开销很小,并且可以使您避免许多愚蠢的错误。您是否有足够的理由取消此功能并在各处使用集合/容器来支持您的自定义构造?我已经实现了这个分配器——真正的混乱是为实践中所需的所有构造变体创建函子。无论如何,您通常会以牺牲程序为代价获得更精确的执行,而程序通常比每个人都知道的习惯用法更难维护。You've reimplemented
new[]
/delete[]
here, and what you have written is pretty common in developing specialized allocators.The overhead of calling simple constructors will take little time compared the allocation. It's not necessarily 'much more efficient' -- it depends on the complexity of the default constructor, and of
operator=
.One nice thing that has not been mentioned yet is that the array's size is known by
new[]
/delete[]
.delete[]
just does the right and destructs all elements when asked. Dragging an additional variable (or three) around so you exactly how to destroy the array is a pain. A dedicated collection type would be a fine alternative, however.new[]
/delete[]
are preferable for convenience. They introduce little overhead, and could save you from a lot of silly errors. Are you compelled enough to take away this functionality and use a collection/container everywhere to support your custom construction? I've implemented this allocator -- the real mess is creating functors for all the construction variations you need in practice. At any rate, you often have a more exact execution at the expense of a program which is often more difficult to maintain than the idioms everybody knows.恕我直言,两者都很难看,最好使用向量。只要确保提前分配空间以提高性能即可。
或者:
如果您想使用所有条目的默认值进行初始化。
或者,如果您不想构造对象但确实想保留空间:
那么如果您需要将其作为 C 样式指针数组访问(只需确保在保留旧指针的同时不添加内容,但无论如何,你不能用常规的c风格数组来做到这一点。)
访问单个元素:
Typedef for beautiful:
通过引用将它们传递给函数:
编辑:
在 C++11 中还有 std::array。但它的问题是它的大小是通过模板完成的,因此您不能在运行时制作不同大小的大小,并且不能将其传递到函数中,除非它们期望完全相同的大小(或者模板函数本身)。但它对于缓冲区之类的东西很有用。
编辑2:
另外,在 C++11 中,有一个新的 emplace_back 作为 push_back 的替代品。这基本上允许您“移动”您的对象(或直接在向量中构造您的对象)并为您保存一个副本。
IMHO there both ugly, it's better to use vectors. Just make sure to allocate the space in advance for performance.
Either:
If you want to initialize with a default value for all entries.
Or if you don't want to construct the objects but do want to reserve the space:
Then if you need to access it as a C-Style pointer array just (just make sure you don't add stuff while keeping the old pointer but you couldn't do that with regular c-style arrays anyway.)
Access individual elements:
Typedef for pretty:
Pass them around functions with references:
EDIT:
IN C++11 there is also std::array. The problem with it though is it's size is done via a template so you can't make different sized ones at runtime and you cant pass it into functions unless they are expecting that exact same size (or are template functions themselves). But it can be useful for things like buffers.
EDIT2:
Also in C++11 there is a new emplace_back as an alternative to push_back. This basically allows you to 'move' your object (or construct your object directly in the vector) and saves you a copy.
哦,好吧,我在想,鉴于答案的数量,没有理由介入……但我想我和其他人一样被吸引了。让我们来看看
1。为什么您的解决方案被破坏了
首先,您提供的两个片段并不相同。
new[]
正常工作,而您的在出现异常时会严重失败。new[] 的作用是跟踪所构造的对象的数量,因此,如果在调用第三个构造函数期间发生异常,它会正确调用已经存在的第二个对象的析构函数构造的对象。
然而,您的解决方案严重失败:
所以两者显然不相等。 你的坏了
2。 C++11 用于处理原始内存的新设施
在 C++11 中,委员会成员已经意识到我们是多么喜欢摆弄原始内存,并且他们引入了一些设施来帮助我们更高效、更安全地这样做。
检查 cppreference 的
简介。此示例展示了新功能 (*):请注意,
get_temporary_buffer
不会抛出异常,它返回实际已分配内存作为pair< 的第二个成员的元素数量。 /code> (因此
.first
来获取指针)。(*) 或者也许并不像 MooingDuck 所说的那么新。
3。完成此操作的更简单方法
据我所知,您真正需要的是一种类型化内存池,其中某些位置可能未已初始化。
你知道
boost::可选
?它基本上是一个原始内存区域,可以容纳给定类型(模板参数)的一项,但默认情况下没有任何内容。它具有与指针类似的接口,可让您查询内存是否实际被占用。最后,使用就地工厂< /a> 如果有问题,您可以安全地使用它,而无需复制对象。
好吧,您的用例确实看起来像
std::vector<升压::可选 >
对我来说(或者可能是一个双端队列
?)4。建议
最后,如果您真的想自己做,无论是为了学习还是因为没有 STL 容器真正适合您,我建议您将其包装在一个对象中以避免代码遍布各处。
不要忘记:不要重复自己!
使用对象(模板化),您可以在一个位置捕获设计的精髓,然后在任何地方重复使用它。
当然,为什么不在这样做时利用新的 C++11 设施呢:)?
Oh well, I was thinking that given the number of answers there would be no reason to step in... but I guess I am drawn in as the others. Let's go
1. Why your solution is broken
First, the two snippets you presented are not equivalent.
new[]
just works, yours fails horribly in the presence of Exceptions.What
new[]
does under the cover is that it keeps track of the number of objects that were constructed, so that if an exception occurs during say the 3rd constructor call it properly calls the destructor for the 2 already constructed objects.Your solution however fails horribly:
So the two are clearly not equivalent. Yours is broken
2. C++11 new facilities for handling raw memory
In C++11, the comittee members have realized how much we liked fiddling with raw memory and they have introduced facilities to help us doing so more efficiently, and more safely.
Check cppreference's
<memory>
brief. This example shows off the new goodies (*):Note that
get_temporary_buffer
is no-throw, it returns the number of elements for which memory has actually been allocated as a second member of thepair
(thus the.first
to get the pointer).(*) Or perhaps not so new as MooingDuck remarked.
3. Simpler way to get this done
As far as I am concered, what you really seem to be asking for is a kind of typed memory pool, where some emplacements could not have been initialized.
Do you know about
boost::optional
?It is basically an area of raw memory that can fit one item of a given type (template parameter) but defaults with having nothing in instead. It has a similar interface to a pointer and let you query whether or not the memory is actually occupied. Finally, using the In-Place Factories you can safely use it without copying objects if it is a concern.
Well, your use case really looks like a
std::vector< boost::optional<T> >
to me (or perhaps adeque
?)4. Advices
Finally, in case you really want to do it on your own, whether for learning or because no STL container really suits you, I do suggest you wrap this up in an object to avoid the code sprawling all over the place.
Don't forget: Don't Repeat Yourself!
With an object (templated) you can capture the essence of your design in one single place, and then reuse it everywhere.
And of course, why not take advantage of the new C++11 facilities while doing so :) ?
您应该使用
向量
。You should use
vectors
.不管是否教条,这正是所有 STL 容器进行分配和初始化的操作。
他们使用分配器,然后分配未初始化的空间并通过容器构造函数对其进行初始化。
如果这(就像很多人常说的)“不是c++”,标准库怎么能这样实现呢?
如果您只是不想使用 malloc / free,则可以仅使用
new char[]
分配“字节”。这使您可以利用初始化和分配之间的分离,同时仍然利用
新
分配异常机制。请注意,将第一行和最后一行放入; >
myallocator
类中,将第二行和倒数第二行放入myvector
类中,我们有...刚刚重新实现了 std::vectorDogmatic or not, that is exactly what ALL the STL container do to allocate and initialize.
They use an allocator then allocates uninitialized space and initialize it by means of the container constructors.
If this (like many people use to say) "is not c++" how can be the standard library just be implemented like that?
If you just don't want to use malloc / free, you can allocate "bytes" with just
new char[]
This lets you take advantage of the separation between initialization and allocation, still taking adwantage of the
new
allocation exception mechanism.Note that, putting my first and last line into an
myallocator<myobject>
class and the second ands second-last into amyvector<myobject>
class, we have ... just reimplementedstd::vector<myobject, std::allocator<myobject> >
您在这里展示的实际上是使用与系统通用分配器不同的内存分配器时的方法 - 在这种情况下,您将使用分配器 (alloc->malloc(sizeof(my_object))) 分配内存,然后使用放置 new 运算符来初始化它。这在高效的内存管理方面有很多优点,并且在标准模板库中很常见。
What you have shown here is actually the way to go when using a memory allocator different than the system general allocator - in that case you would allocate your memory using the allocator (alloc->malloc(sizeof(my_object))) and then use the placement new operator to initialize it. This has many advantages in efficient memory management and quite common in the standard template library.
如果您正在编写一个模仿 std::vector 功能的类或需要控制内存分配/对象创建(在数组中插入/删除等) - 这就是要走的路。在这种情况下,这不是“不调用默认构造函数”的问题。这就变成了一个能够“分配原始内存、
memmove
旧对象,然后在旧对象的地址创建新对象”的问题,以及能够使用某种形式的realloc<的问题。 /代码>等等。毫无疑问,自定义分配+放置
new
更加灵活......我知道,我有点醉了,但是std::vector
适合胆小鬼......效率 - 人们可以编写自己的std::vector
版本,该版本至少与最常用的一样快(并且很可能更小,就sizeof()
而言) 80%的std::vector
功能可能需要不到 3 小时。If you are writing a class that mimics functionality of
std::vector
or needs control over memory allocation/object creation (insertion in array / deletion etc.) - that's the way to go. In this case, it's not a question of "not calling default constructor". It becomes a question of being able to "allocate raw memory,memmove
old objects there and then create new objects at the olds' addresses", question of being able to use some form ofrealloc
and so on. Unquestionably, custom allocation + placementnew
are way more flexible... I know, I'm a bit drunk, butstd::vector
is for sissies... About efficiency - one can write their own version ofstd::vector
that will be AT LEAST as fast ( and most likely smaller, in terms ofsizeof()
) with most used 80% ofstd::vector
functionality in, probably, less than 3 hours.这将是一个包含对象的数组。
这将是一个与对象大小相同的数组,但它们可能会“损坏”。例如,如果您的类有虚拟函数,那么您将无法调用它们。请注意,不仅仅是您的成员数据可能不一致,而且整个对象实际上是“损坏的”(缺乏更好的词)
我并不是说执行第二个是错误的,只要您知道这一点。
This will be an array with objects.
This will be an array the size of your objects, but they may be "broken". If your class has virtual funcitons for instance, then you won't be able to call those. Note that it's not just your member data that may be inconsistent, but the entire object is actully "broken" (in lack of a better word)
I'm not saying it's wrong to do the second one, just as long as you know this.