Подтвердить что ты не робот

С++: новый вызов, который ведет себя как calloc?

Есть ли вызов, который я могу сделать для new, чтобы получить нулевую память, например calloc?

4b9b3361

Ответ 1

Вопреки тому, что некоторые говорят в своих ответах, это возможно.

char * c = new char[N]();

Будет нулевой инициализировать все символы (в действительности он называется инициализацией значения. Но инициализация значения будет нулевой инициализацией для всех ее членов массива скалярного типа). Если это то, что тебе нужно.

Стоит отметить, что он также работает для (классов массивов) типов классов без объявленного конструктора, и в этом случае любой из них инициализируется значением:

struct T { int a; };
T *t = new T[1]();
assert(t[0].a == 0);
delete[] t;

Это не какое-то расширение или что-то еще. Он работал и вел себя так же и в С++ 98. Именно там он назывался инициализацией по умолчанию вместо инициализации значения. Однако инициализация нуля выполняется в обоих случаях для скаляров или массивов скалярных или POD-типов.

Ответ 2

Нет, но довольно легко создать новую версию, которая действует как calloc. Это можно сделать почти так же, как реализована новая версия new-throw.

SomeFile.h

struct zeromemory_t{};
extern const zeromemory_t zeromemory;
void* __cdcel operator new(size_t cbSize, const zeromemory_t&);

SomeFile.cpp

const zeromemory_t zeromemory;

void* _cdecl operator new(size_t cbSize, const zeromemory_t&)
{
    void *mem = ::operator new(cbSize);
    memset(mem,0,cbSize);
    return mem;
}

Теперь вы можете сделать следующее, чтобы получить новое с нулевой памятью

MyType* pMyType = new (zeromemory) MyType();

Кроме того, вам нужно будет делать другие забавные вещи, такие как define new [], что также довольно прямолинейно.

Ответ 3

Нет. Также даже не думайте делать что-то вроде:

YourClass *var = new YourClass;
memset(var, 0, sizeof(YourClass));

В итоге вы можете уничтожить VTABLE (если ваш класс имеет один).

Я бы рекомендовал использовать конструкторы для очистки внутренней памяти (переменных) вашего класса.

Ответ 4

Неа. Он всегда будет по умолчанию инициализировать выделенный элемент (ы), который в случае примитивов ничего не делает. Вам нужно будет выполнить его с помощью вызова std:: uninitialized_fill_n или подобного.

Ответ 5

Вы можете сделать глобальную перегрузку оператора new и захватить необработанную память из calloc(). Таким образом, память стирается до запуска конструкторов, поэтому проблем там нет.

Любой класс, который переопределяет новый сам по себе, не получит ваш специальный calloc() -уложенный new, но тогда этот класс должен быть инициализирован правильно в любом случае.

Не забудьте переопределить как new, так и delete и версии массивов...

Что-то вроде:

#include <exception> // for std::bad_alloc
#include <new>
#include <stdlib.h> // for calloc() and free()

void* operator new (size_t size)
{
 void *p=calloc(size, 1); 
 if (p==0) // did allocation succeed?
  throw std::bad_alloc(); 
 return p;
}


void operator delete (void *p)
{
 free(p); 
}

void* operator new[] (size_t size)
{
 void *p=calloc(size, 1); 
 if (p==0) // did allocation succeed?
  throw std::bad_alloc();
 return p;
}

void operator delete[] (void *p)
{
 free(p); 
}

Обратите внимание, что эти простые версии не совсем то, что они должны быть - оператор new должен запускаться в цикле, вызывающем new_handler (если он установлен), и только бросает исключение bad_alloc, если есть нет new_handler. Или что-то в этом роде, мне придется искать его и обновлять позже.

О, и вы можете также переопределить версию no_throw.

Ответ 6

Я использую макрос:

#define newclear(TYPE) new(calloc(sizeof(TYPE), 1)) TYPE();

чтобы использовать его:

Whatever* myWhatever = newclear(Whatever);

(здесь используется "размещение нового", как и некоторые другие решения)

Ответ 7

Нет. Вы должны вручную отключить память. Помните, что new - это не только выделение памяти, но и инициализация через конструкторы. Здесь calloc удобен в C (который не имеет функций инициализации). Вы можете писать обертку поверх new или даже использовать calloc, но большую часть времени для объектов, отличных от POD, это не имеет особого смысла.

Ответ 8

если вы не настаиваете на использовании new, вы можете просто использовать вектор: vector<char> buffer; buffer.resize(newsize);, и содержимое будет обнулено.

Ответ 9

Да.

int* p_scalar = new int(5);//Does not create 5 elements, but initializes to 5

Для массивов вы можете использовать что-то вроде memset. Для окон используются ZeroMemory или SecureZeroMemory.

Изменить:. См. сообщение @litb, он показывает, как вы можете инициализировать до 0 для массивов, используя не прямую инициализацию, как указано выше.

Ответ 10

class MyClass {
    public:
    void* operator new(size_t bytes) {
        return calloc(bytes, 1);
    }
}

И вы можете переопределить глобальный новый оператор, если хотите.

Ответ 11

Вы можете сказать:

vector <char> v( 100, 0 );

который создает смежный массив из 100 символов с помощью new и инициализирует их все до нуля. Затем вы можете получить доступ к массиву с помощью оператора vector [] или выполнить:

char * p = &v[0];
p[3] = 42;

Обратите внимание, что это также освобождает вас от необходимости вызывать удаление, чтобы освободить выделенную память.