C++ 运算符new()和运算符new[]()之间的区别?

C++ 运算符new()和运算符new[]()之间的区别?,c++,memory,C++,Memory,FNC:新操作员和新操作员[](不是新操作员和新操作员[])之间是否有任何区别?当然除了调用语法?我这样问是因为我可以用::operator new(sizeof(T)*numberOfObject)为我的obj分配X个字节,然后用数组表示法访问它们,那么::operator new[]有什么大不了的呢。只是语法上的糖吗 #include <new> #include <iostream> #include <malloc.h> using namespac

FNC:新操作员和新操作员[](不是新操作员和新操作员[])之间是否有任何区别?当然除了调用语法?我这样问是因为我可以用::operator new(sizeof(T)*numberOfObject)为我的obj分配X个字节,然后用数组表示法访问它们,那么::operator new[]有什么大不了的呢。只是语法上的糖吗

#include <new>
#include <iostream>
#include <malloc.h>

using namespace std;
struct X
{
  int data_;
  X(int v):data_(v){}
};
int _tmain(int argc, _TCHAR* argv[])
{
  unsigned no = 10;
  void* vp = ::operator new(sizeof(X) * no);
  cout << "Mem reserved: " << _msize(vp) << '\n';
  X* xp = static_cast<X*>(vp);
  for (unsigned i = 0; i < no; ++i)
  {
    new (xp + i) X(i);
  }
  for (unsigned i = 0; i < no; ++i)
  {
    cout << (xp[i]).data_ << '\n';
  }
  for (unsigned i = 0; i < no; ++i)
  {
    (xp + i)->~X();
  }
  ::operator delete(vp);
  return 0;
}
#包括
#包括
#包括
使用名称空间std;
结构X
{
int数据;
X(intv):数据_v{}
};
int _tmain(int argc,_TCHAR*argv[]
{
无符号编号=10;
void*vp=::运算符新(sizeof(X)*否);

cout函数的所需行为
void*operator new(size\u t)
void*operator new[](size\u t)
之间没有太大区别,只是它们与不同的释放函数配对

运算符本身是非常不同的。运算符之间的差异之一是使用了哪个分配函数,但最终还有许多其他差异,包括调用了多少构造函数等。但是您的示例代码没有使用运算符(好吧,它使用的是placement new)。您可能需要更改问题标题以明确这一点

从节
[basic.stc.dynamic.deallocation]

如果解除分配函数终止 通过抛出异常,该行为 未定义。第一个 提供给解除分配的参数 函数可以是空指针值; 如果是,如果取消分配 函数是在 标准库,调用没有 效果。否则,值 提供给中的操作员删除(无效*)
标准库应为下列之一: 前一个函数返回的值 调用任一运算符
新(标准::尺寸)
或操作员
new(std::size\u t,const std::nothrow_-
t&)
在标准库中,以及 提供给
运算符的值
删除标准中的[](无效*)
库应为其中一个值 由以前调用的返回
操作员新[](标准::大小\u t)
运算符新[](标准::大小,常数
标准中的std::nothrow\u t&
图书馆


分配是一回事,对象构建/销毁是另一回事。

new
执行一次分配和一次构造。然而,
new[]
仍然分配一个连续内存块,但调用许多构造函数

delete
delete[]
的情况相同

顺便说一句-我不是100%确定我要说的话,但我相信如果您对从
new[]收到的地址调用
delete
,您不会得到IMemidate内存泄漏
。整个内存块可能会被释放。但是,这是无效的,因为您只对第一个对象调用析构函数,而不是对数组中的每个对象调用析构函数。这可能会导致二次内存泄漏……当然,由于构造函数和析构函数的1-1关系被破坏,会导致许多逻辑错误


(也请记住使用<代码> Boo::<代码> STD::vector < <代码> new []/COD>!:):

< P>在您的示例代码中,您使用布局<代码> new <代码>来执行<代码>操作符new []/Cuffe自动执行的构造-与代码<新>不同将只执行默认构造,而您正在执行非默认放置构造

以下内容大致相当于您的示例:

#include <iostream>

using namespace std;

struct X
{
    int data_;
    X(int v=0):data_(v){}
};

int main(int argc, char* argv[])
{
    unsigned no = 10;

    X* xp = new X[no];

    for (unsigned i = 0; i < no; ++i) {
        X tmp(i);
        xp[i] = tmp;
    }

    for (unsigned i = 0; i < no; ++i)
    {
        cout << (xp[i]).data_ << '\n';
    }

    delete[] xp;

    return 0;
}
#包括
使用名称空间std;
结构X
{
int数据;
X(intv=0):数据_v(v){
};
int main(int argc,char*argv[])
{
无符号编号=10;
X*xp=新X[否];
for(无符号i=0;ioperator new
等)通常不打算显式调用,而是由
new
/
new[]
表达式隐式使用(对称地,
operator delete
/
operator delete[]隐式调用
delete
函数
expressions)。对非数组类型使用
new
语法的表达式将隐式调用
operator new
函数,而带有
new[]
的表达式将隐式调用
operator new[]

这里的重要细节是,由
new[]
expression创建的数组通常稍后将由
delete[]
expression销毁。后者需要知道要销毁的对象的数量(如果对象具有非平凡的析构函数),即必须以某种方式从
new[]
expression传递此信息(已知时)对应的
delete[]
表达式(需要时)。在典型实现中,此信息存储在
new[]
表达式分配的块内,这就是对
操作符new[]的隐式调用中请求的内存大小的原因
通常大于元素数量与元素大小的乘积。额外空间用于存储家庭信息(即元素数量)。稍后
删除[]
expression将检索该家庭信息并使用它调用正确数量的析构函数,然后通过调用
operator delete[]实际释放内存。

在您的示例中,您没有使用这些机制中的任何一种。在您的示例中,您显式调用内存分配函数,手动执行构造并完全忽略销毁步骤(这是可以的,因为您的对象具有普通的析构函数),这意味着至少出于销毁目的,您不需要跟踪数组中元素的确切数量。在任何情况下,您都可以跟踪该元素