使用参数构造函数模拟 new[]

发布于 2024-11-08 19:17:07 字数 535 浏览 0 评论 0原文

如果我没有修改参数构造函数内的任何static变量,则低于模拟new T[N] (x,y);(带参数的数组new)的正确方法)?

template<typename T>
void* operator new [] (size_t size, const T &value)
{
  T* p = (T*) malloc(size);
  for(int i = size / sizeof(T) - 1; i >= 0; i--)
    memcpy(p + i, &value, sizeof(T));
  return p;
}

用法将是,

struct A
{
  A () {}  // default
  A (int i, int j) {} // with arguments
};

int main ()
{
  A *p = new(A(1,2)) A[10];  // instead of new A[10](1,2)
}

If I am not modifying any static variable inside the argument constructor, is below the proper way to simulate new T[N] (x,y); (array new with arguments) ?

template<typename T>
void* operator new [] (size_t size, const T &value)
{
  T* p = (T*) malloc(size);
  for(int i = size / sizeof(T) - 1; i >= 0; i--)
    memcpy(p + i, &value, sizeof(T));
  return p;
}

Usage will be,

struct A
{
  A () {}  // default
  A (int i, int j) {} // with arguments
};

int main ()
{
  A *p = new(A(1,2)) A[10];  // instead of new A[10](1,2)
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北陌 2024-11-15 19:17:07

我建议

 std::vector<A> v(10, A(1,2));

我意识到这并不能真正解决数组的问题。
您可以使用,

 p = &v[0]; 

因为该标准保证连续存储。不过,调整向量大小时要非常小心,因为它可能会使 p 无效,

我检查了 boost::array<> (它适应 C 风格数组),但它没有定义构造函数......

I'd suggest

 std::vector<A> v(10, A(1,2));

I realize that this doesn't really address the question for arrays.
You could use

 p = &v[0]; 

since the standard guarantees contiguous storage. Be very careful with resizing the vector though, because it could invalidate p

I checked boost::array<> (which adapts C style arrays), but it doesn't define constructors...

没有伤那来痛 2024-11-15 19:17:07

不行。您将对象复制到未初始化的内存中,而没有调用正确的复制语义。

只要您只使用 POD,就可以了。但是,当使用不是 POD 的对象(例如您的 A)时,您需要采取预防措施。

除此之外,operator new 不能以这种方式使用。正如 Alexandre 在评论中指出的那样,该数组将无法正确初始化,因为 C++ 将调用所有的构造函数调用你的operator new之后的元素,从而覆盖这些值:

#include <cstdlib>
#include <iostream>

template<typename T>
void* operator new [] (size_t size, T value) {
    T* p = (T*) std::malloc(size);
    for(int i = size / sizeof(T) - 1; i >= 0; i--)
        new(p + i) T(value);
    return p;
}

struct A {
    int x;
    A(int x) : x(x) { std::cout << "int ctor\n"; }
    A() : x(0) { std::cout << "default ctor\n"; }
    A(const A& other) : x(other.x) { std::cout << "copy ctor\n"; }
};

int main() {
    A *p = new(A(42)) A[2];
    for (unsigned i = 0; i < 2; ++i)
        std::cout << p[i].x << std::endl;
}

这会产生:

int ctor
copy ctor
copy ctor
default ctor
default ctor
0
0

……不是期望的结果。

This isn’t OK. You are copying objects into uninitialised memory without invoking proper copy semantics.

As long as you’re only working with PODs, this is fine. However, when working with objects that are not PODs (such as your A) you need to take precautions.

Apart from that, operator new cannot be used in this way. As Alexandre has pointed out in the comments, the array won’t be initialised properly since C++ will call constructors for all elements after having called your operator new, thus overriding the values:

#include <cstdlib>
#include <iostream>

template<typename T>
void* operator new [] (size_t size, T value) {
    T* p = (T*) std::malloc(size);
    for(int i = size / sizeof(T) - 1; i >= 0; i--)
        new(p + i) T(value);
    return p;
}

struct A {
    int x;
    A(int x) : x(x) { std::cout << "int ctor\n"; }
    A() : x(0) { std::cout << "default ctor\n"; }
    A(const A& other) : x(other.x) { std::cout << "copy ctor\n"; }
};

int main() {
    A *p = new(A(42)) A[2];
    for (unsigned i = 0; i < 2; ++i)
        std::cout << p[i].x << std::endl;
}

This yields:

int ctor
copy ctor
copy ctor
default ctor
default ctor
0
0

… not the desired outcome.

阳光下慵懒的猫 2024-11-15 19:17:07

这是不行的 - 如果 typename T 有这样的对象(您的示例中的 struct A 确实有一个),C++ 将调用这些对象的非平凡默认构造函数,这将导致重建对象内存中已被占用。

适当的解决方案是使用 std::vector (推荐)或调用 ::operator new[] 来分配内存,然后使用placement-new调用构造函数并注意例外情况(如果有)。

That's not okay - C++ will call those objects non-trivial default constructors if typename T has such (struct A in your example does have one) and that would lead to reconstructing objects in memory already occupied.

An appropriate solution would be to use std::vector (recommended) or call ::operator new[] to allocate memory, then call constructors using placement-new and taking care of exceptions if any.

夏尔 2024-11-15 19:17:07

您应该考虑到可能会调用operator new[],要求比裸露的sizeof(T) * n更多的内存。

可能需要这个额外的内存,因为 C++ 必须知道在 delete[] p; 的情况下要销毁多少对象,但它无法可靠地使用 new p[sz 分配的内存块的大小] 来推断这个数字,因为内存可能已被请求给自定义内存管理器,因此(例如您的情况)无法仅通过知道指针来知道分配了多少内存。

这也意味着您尝试提供已初始化的对象将会失败,因为返回到应用程序的实际数组可能不会从您从自定义operator new[] 返回的地址开始,因此初始化可能会错位。

You should consider that operator new[] may be called asking for more memory than the bare amount sizeof(T) * n.

This extra memory is possibly needed because C++ must know how many object to destroy in case of delete[] p; but it cannot reliably use the size of block of memory allocated by new p[sz] to infer this number because the memory may have been asked to a custom memory manager so (e.g. your case) there is no way to know how much memory was allocated only by knowing the pointer.

This also means that your attempt to provide already-initialized objects will fail because the actually array returned to the application will potentially not start at the address you returned from your custom operator new[] so that initialization could be misaligned.

-黛色若梦 2024-11-15 19:17:07
template <typename myType> myType * buildArray(size_t numElements,const myType & startValue) {
  myType * newArray=(myType *)malloc(sizeof(myType)*numElements);

  if (NULL!=newArray) {
    size_t index;
    for (index=0;index<numElements;++index) {
      new (newArray+index) myType(startValue);
    }
  }

  return newArray;
}

template <typename myType> void destroyArray(size_t numElements,myType * oldArray) {
  size_t index;
  for (index=0;index<numElements;++index) {
    (oldArray+index)->~myType();
  }
  free(oldArray);
}

A * p=newArray(10,A(1,2));
destroyArray(10,p);

destroyArray 也可以这样写,具体取决于您构建的平台:

template <typename myType> void destroyArray(myType * oldArray) {
  size_t numElements=malloc_size(oldArray)/sizeof(myType); //or _msize with Visual Studio
  size_t index;
  for (index=0;index<numElements;++index) {
    (oldArray+index)->~myType();
  }
  free(oldArray);
}
template <typename myType> myType * buildArray(size_t numElements,const myType & startValue) {
  myType * newArray=(myType *)malloc(sizeof(myType)*numElements);

  if (NULL!=newArray) {
    size_t index;
    for (index=0;index<numElements;++index) {
      new (newArray+index) myType(startValue);
    }
  }

  return newArray;
}

template <typename myType> void destroyArray(size_t numElements,myType * oldArray) {
  size_t index;
  for (index=0;index<numElements;++index) {
    (oldArray+index)->~myType();
  }
  free(oldArray);
}

A * p=newArray(10,A(1,2));
destroyArray(10,p);

destroyArray could also be written like this depending on the platform you are building for:

template <typename myType> void destroyArray(myType * oldArray) {
  size_t numElements=malloc_size(oldArray)/sizeof(myType); //or _msize with Visual Studio
  size_t index;
  for (index=0;index<numElements;++index) {
    (oldArray+index)->~myType();
  }
  free(oldArray);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文