C++中的内存分配

8

使用“new”运算符是否可能分配任意内存块? 在C语言中,我可以这样做:“void * p = malloc(7);” - 如果内存对齐设置为1字节,则会分配7个字节。如何在C++中使用new运算符实现同样的效果?

8个回答

45

在C++中可以使用operator new分配任意大小的内存块,但不能使用用于构造对象的new运算符。

void* pBlock = ::operator new(7);

这样的内存块可以使用operator delete进行释放。

::operator delete(pBlock);

请注意,operator new将为任何类型的对象分配适当对齐的内存,因此实现可能不会精确地分配七个字节而不多,但malloc通常也是如此。 C客户端通常也需要对齐的内存。


7
谢谢您提到了一种不需要使用malloc和free的方法,给您点个赞 :) - Johannes Schaub - litb
1
此外,请注意,operator new通常只是将任务转交给malloc()(在我所知道的每个实现中都是如此)。正如Dominic所说,最好直接使用malloc。 - Drew Hall
1
非常感谢。这就是一个答案("::operator new")。我花了很多时间试图弄清楚为什么"::new(x);"不起作用 :) - user132349

11

其他人已根据问题提供了答案,但我想建议在这种情况下坚持使用malloc/free进行分配。

new和delete用于分配对象。它们分配所需的内存并调用构造函数/析构函数。如果您知道只需要任意块的内存,则使用malloc和free是完全合理的。


1
但是如果你正在编写C++代码,我认为最好使用new/delete,因为你将使用它来分配对象。拥有两种类型的内存分配函数会增加更多的混淆。 - Naveen
1
-1. new/delete 是语言结构,无论你如何分配/释放内存,它们都引入了类型安全。malloc/free 则是为了保持向后兼容而遗留下来的产物。 - sharkin
1
@RA,如果需要一个任意的通用字节块,那么假装它们是特定的char或unsigned char或其他类型是没有意义的——void*更加诚实和明确。malloc加1! - Alex Martelli
该OP明确表示他们希望返回一个空指针。因此,使用new/delete将在不需要的情况下引入类型。如果实际用例将作为类型数组,则绝对要切换到new[]。如果他们只是管理一块内存,则没有理由引入类型。 - dma
从这里+1。是的,new/delete增加了类型安全性,但如果他不想分配任何特定类型,而只是一个空的内存缓冲区,那么malloc/free正好做到了这一点。 - jalf
虽然你应该像被接受的答案一样使用operator new,因为它们可能被覆盖以执行某些操作。 - GManNickG

8

您不能使用C++的new运算符分配一个void指针:您需要分配一个显式类型,如charuint8_t

char *p = new char[7];
uint8_t *q = new uint8_t[7];
...
delete [] p;
delete [] q;

3

个人建议使用std::vector<char>。不仅可以获得任意块的字节(保证连续),还可以在RAII封装器中获得它们。当然,除了resize()之外,没有必要使用std::vector的任何方法,但没有任何惩罚:

std::vector<char> buffer(7);
void* p = &buffer[0];

您可以使用std::string,但是std::string意味着“此对象包含可打印的字符”,而std::vector<char>则表示“此对象包含任意字节组”。

3

是的,你可以这样做。
但是根据你所做的事情,可能会有更好的技术。

能否更新问题并告诉我们你想要实现什么。提供更多上下文,可以提供更好的解决方案。

例如:
如果你正在动态分配一个缓冲区来从套接字中读取(因为大小在编译时未知),那么另一种选择是使用向量并动态调整其大小。然后,通过获取第一个元素的地址,可以得到指向缓冲区内部的指针。


2

1
我只想补充一点,如果你将要使用像Placement New这样的技术,你必须非常小心。只有在真正必要的情况下才使用它!! - Mike Dinescu
5
placement new(定位new)和内存分配有什么关系? - avakar
@Miky D:我同意,这就是为什么链接页面上都用大写字母“危险”来标注的原因。 :-) - Michael Kristofik
4
也许我误解了问题,但我认为它所问的正好相反。也就是说,不是如何在已分配的内存空间中创建/初始化对象,而是如何分配内存而不执行构造函数调用。 - David Rodríguez - dribeas

2

新建一个 char[7] 的数组。

传统上,char 是一个字节,尽管你可能会发现一些库将其 typedef 为 BYTE 类型。


5
无关紧要;char是实现可以处理的最小类型。如果一个char是16位,那么byte类型不得小于16位。请记住sizeof(char) == 1,始终如此。 - David Thornley
@David Thornley:sizeof(char) 不一定是1,否则各种编组库都会出现严重问题。 - florin
1
@florin:根据标准,sizeof(char)等于1。请参阅ISO/IEC 14882:2003的第5.3.3节。“sizeof(char),sizeof(signed char)和sizeof(unsigned char)都是1;对于任何其他基本类型(3.9.1)应用sizeof的结果是实现定义的。” - Evan Teran
1
嗯,是的,sizeof(char) == 1。至少根据ISO C++标准的5.3.3节(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf),但让我们不要无聊,我更喜欢对这个问题的回答:http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.1。 - Andreas Magnusson
@Andreas:这不就是我刚才说的吗? - Evan Teran
@Evan:我和你同时写了评论。在我按下按钮之前,你的评论还没有显示出来。由于我的评论中有一些好的参考资料,所以我决定保留它,即使它基本上说的是同样的事情。 - Andreas Magnusson

2

您可以执行char* pBuffer = new char[7];,由于char大小为1字节,因此您可以将其用作字节缓冲区。另外,在释放内存时,请记得使用delete[](带有[])。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接