8

我有一个这样描述的课程:

class Foo {
    int size;
    int data[0];

public:
    Foo(int _size, int* _data) : size(_size) {
        for (int i = 0 ; i < size ; i++) {
            data[i] = adapt(_data[i]);
        }
    }

    // Other, uninteresting methods
}

我无法更改该课程的设计。

如何创建该类的实例?在调用构造函数之前,我必须让它保留足够的内存来存储它的数据,所以它必须在堆上,而不是在栈上。我想我想要类似的东西

Foo* place = static_cast<Foo*>(malloc(sizeof(int) + sizeof(int) * size));
*place = new Foo(size, data);  // I mean : "use the memory allocated in place to do your stuff !"

但我找不到让它工作的方法。

编辑:正如评论员所注意到的,这不是一个很好的整体设计(使用非标准技巧,例如data[0]),唉,这是一个我被迫使用的库......

4

4 回答 4

11

您可以malloc使用对象的内存,然后使用 aplacement new在先前分配的内存中创建对象:

void* memory = malloc(sizeof(Foo) + sizeof(int) * size);
Foo* foo = new (memory) Foo(size, data);

请注意,为了销毁此对象,您不能使用delete. 您必须手动调用析构函数,然后free在分配的内存上使用malloc

foo->~Foo();
free(memory); //or free(foo);

另请注意,正如@Nikos C.@GManNickG 所建议的,您可以使用以下方式以更C++ 的方式执行相同操作::operator new

void* memory = ::operator new(sizeof(Foo) + sizeof(int) * size);
Foo* foo = new (memory) Foo(size, data);
...
foo->~Foo();
::operator delete(memory); //or ::operator delete(foo);
于 2013-05-30T14:38:55.863 回答
8

你有一个库可以做这件事但不提供工厂函数?耻辱!

无论如何,虽然 zakinster 的方法是正确的(不过,我会直接调用 operator new 而不是新建一个字符数组),但它也容易出错,所以你应该把它包起来。

struct raw_delete {
  void operator ()(void* ptr) {
    ::operator delete(ptr);
  }
};

template <typename T>
struct destroy_and_delete {
  void operator ()(T* ptr) {
    if (ptr) {
      ptr->~T();
      ::operator delete(ptr);
    }
  }
};
template <typename T>
using dd_unique_ptr = std::unique_ptr<T, destroy_and_delete<T>>;

using FooUniquePtr = dd_unique_ptr<Foo>;

FooUniquePtr CreateFoo(int* data, int size) {
  std::unique_ptr<void, raw_delete> memory{
    ::operator new(sizeof(Foo) + size * sizeof(int))
  };
  Foo* result = new (memory.get()) Foo(size, data);
  memory.release();
  return FooUniquePtr{result};
}

是的,这里有一点开销,但是这些东西大部分都是可重用的。

于 2013-05-30T16:01:54.133 回答
1

If you really want to be lazy simply use a std::vector<Foo>. It will use more space (I think 3 pointers instead of 1) but you get all the benefits of a container and really no downsides if you know it is never going to change in size.

Your objects will be movable given your definition so you can safely do the following to eliminate reallocation of the vector during initial fill...

auto initialFooValue = Foo(0, 0)
auto fooContainer = std::vector<Foo>(size, initialFooValue);

int i = 0;
for (auto& moveFoo : whereverYouAreFillingFrom)
{
    fooContainer[i] = std::move(moveFoo);
    ++i;
}

Since std::vector is contiguous you can also just memcopy into it safely since your objects are trivially-copyable.

于 2013-05-30T14:58:41.260 回答
1

我认为一个好的C++ 解决方案是使用 new 获取原始内存,然后使用placement new 将您的类嵌入其中。

获取原始内存的工作方式如下:

Foo *f = static_cast<Foo *>(operator new(sizeof(Foo)); 

在接收到的内存中构造对象的工作方式如下:

new (f) Foo(size, data); // placement new

请记住,这也意味着您必须手动清理该位置。

f->~Foo(); // call the destructor
operator delete(f); // free the memory again

malloc我个人的看法是,free在新编写的 C++ 代码中使用它是不好的。

于 2013-05-31T17:11:31.977 回答