C++: nowe połączenie, które zachowuje się jak calloc?

Czy Jest jakiś telefon do new żeby mieć zerową pamięć jak calloc?

Author: banarun, 2009-04-30

11 answers

Wbrew temu, co niektórzy mówią w swoich odpowiedziach, tojest możliwe.

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

Spowoduje, że zero zainicjalizuje wszystkie znaki (w rzeczywistości nazywa się to inicjalizacją wartości. Ale inicjalizacja wartości będzie zerową inicjalizacją dla wszystkich jej członków tablicy typu scalar). Jeśli o to ci chodzi.

Warto zauważyć, że działa również dla (tablic) typów klas bez deklarowanego przez użytkownika konstruktora, w którym to przypadku każdy z nich jest wartością inicjalizacja:

struct T { int a; };
T *t = new T[1]();
assert(t[0].a == 0);
delete[] t;
To nie jest jakieś rozszerzenie. Działał i zachowywał się podobnie również w C++98. Właśnie tam została nazwana domyślna inicjalizacja zamiast inicjalizacji wartości. Inicjalizacja zerowa jest jednak wykonywana w obu przypadkach dla skalarów lub tablic typu Skalar lub POD.
 72
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 19:11:04

Nie, ale dość łatwo jest stworzyć nową wersję, która działa jak calloc. Można to zrobić w taki sam sposób, jak zaimplementowana jest wersja No-throw new.

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;
}

Teraz możesz wykonać następujące czynności, aby uzyskać nowy z zerową pamięcią

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

Dodatkowo musisz robić inne zabawne rzeczy, takie jak define new [], które są również dość proste.

 11
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 20:20:31

Nie. Nawet nie myśl o zrobieniu czegoś takiego:

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

Możesz skończyć niszcząc swój VTABLE(jeśli twoja klasa ma taki).

Zalecałbym użycie konstruktorów do wyczyszczenia pamięci wewnętrznej (zmiennych) twojej klasy.

 5
Author: Pablo Santa Cruz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 18:52:10

Nie. Zawsze będzie domyślnie-inicjalizuje przydzielone elementy,co w przypadku prymitywów nic nie robi. Musisz to sprawdzić wywołaniem std::uninitialized_fill_n lub podobnym.

 2
Author: Promit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 18:44:52

Możesz wykonać globalne przeciążenie operatora new i zmusić go do przechwycenia nieprzetworzonej pamięci z calloc(). W ten sposób pamięć zostaje wyczyszczona przed uruchomieniem konstruktorów, więc nie ma żadnych problemów.

Każda klasa, która sama nadpisuje new, nie otrzyma twojego Specjalnego calloc() opartego na new, ale ta klasa i tak powinna być inicjalizowana poprawnie.

Nie zapomnij nadpisać zarówno new i delete oraz wersji tablicy...

Coś w stylu:

#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); 
}

Uwaga że te proste wersje nie są dokładnie takie, jakie powinny być - operator new powinien działać w pętli wywołując new_handler (jeśli jest zainstalowany) i rzucając wyjątek bad_alloc tylko wtedy, gdy nie ma new_handler. Albo coś w tym stylu, będę musiał to sprawdzić i zaktualizować później.

Oh, i możesz chcieć także zastąpić wersję no_throw.
 2
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 19:04:04

Używam makra:

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

Aby go użyć:

Whatever* myWhatever = newclear(Whatever);

(używa się tu "umieszczania nowego", jak niektóre inne rozwiązania tutaj)

 1
Author: Martijn Scheffer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-13 18:53:53

Nie.Musisz ręcznie wyzerować pamięć. Pamiętaj, new nie chodzi tylko o przydzielanie pamięci, ale także o inicjowanie za pomocą konstruktorów. To jest miejsce, gdzie calloc jest przydatne w C (który nie ma funkcji inicjalizatora). Możesz napisać wrapper nad new lub nawet użyć calloc, ale większość czasu dla obiektów spoza POD nie ma to większego sensu.

 0
Author: dirkgently,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 18:46:06

Jeśli nie nalegasz na użycie new, możesz po prostu użyć vector: vector<char> buffer; buffer.resize(newsize);, a zawartość zostanie zerowana.

 0
Author: Francis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 18:50:08
class MyClass {
    public:
    void* operator new(size_t bytes) {
        return calloc(bytes, 1);
    }
}

I możesz zastąpić globalny nowy operator, jeśli chcesz.

 0
Author: Unknown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 18:52:01

Możesz powiedzieć:

vector <char> v( 100, 0 );

, który tworzy ciągłą tablicę 100 znaków używając new i inicjalizuje je wszystkie do zera. Następnie można uzyskać dostęp do tablicy za pomocą operatora wektora [] lub wykonując:

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

Uwaga uwalnia to również od konieczności wywoływania delete w celu uwolnienia przydzielonej pamięci.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 19:02:12

Tak.

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

Dla tablic można użyć czegoś takiego jak memset. Dla systemu windows użyj ZeroMemory lub SecureZeroMemory.

Edit: proszę zobaczyć post @ litb, pokazuje on, jak można zainicjować do 0 dla tablic za pomocą inicjalizacji Nie bezpośredniej, jak powyżej.

 0
Author: Brian R. Bondy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 19:18:47