2010-03-20 16 views
14

Plik memset jest czasami używany do inicjowania danych w konstruktorze, jak w przykładzie poniżej. Czy to działa ogólnie? Czy to ogólnie dobry pomysł?Przydział do inicjalizacji w C++

class A { 
public: 
    A(); 
private: 
    int a; 
    float f; 
    char str[35]; 
    long *lp; 
}; 

A::A() 
{ 
    memset(this, 0, sizeof(*this)); 
} 
+0

Możesz użyć następującego podejścia: http://stackoverflow.com/a/38103250/3223828 –

Odpowiedz

21

Nie używaj memset. Jest to zatrzymanie z C i nie będzie działać na urządzeniach innych niż POD. W szczególności użycie go w klasie pochodnej, która zawiera jakiekolwiek funkcje wirtualne - lub dowolna klasa zawierająca nie-wbudowaną - spowoduje katastrofę.

C++ zapewnia specyficzną składnię dla inicjalizacji:

class A { 
public: 
    A(); 
private: 
    int a; 
    float f; 
    char str[35]; 
    long *lp; 
}; 

A::A() 
    : a(0), f(0), str(), lp(NULL) 
{ 
} 

Szczerze mówiąc, nie jestem pewien, ale memset może również być zły pomysł na pływających punktów od ich format jest nieokreślona.

+1

Istnieje również 'std :: fill' lub' std :: fill_n', jeśli potrzebujesz "zmontować" tablicę (lub dowolną inną sekwencję) – jalf

+0

Dla tablicy przypadku lepiej jest zrobić 'str()' .GCC ma problemy z inicjalizacją tablicy char przez literał ciągu poprzez inicjator-członka, a jeśli tablica nie jest tablicą char, to nie będzie działać nawet w standardowym kompilatorze. ' str() 'zawsze niweluje tablicę. (Właśnie wysłałem raport o błędzie: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43453) –

+0

@litb: Zauważono i zmieniono powyżej. – rlbond

12

To okropny pomysł. Po prostu miażdżysz dane, nie zwracając uwagi na sposób inicjowania obiektów. Jeśli twoja klasa jest wirtualna, prawdopodobnie zlikwidujesz również wskaźnik vtable.

memset działa na surowych danych, ale w C++ nie chodzi o surowe dane. C++ tworzy abstrakcje, więc jeśli chcesz być bezpieczny, korzystasz z tych abstrakcji. Użyj listy inicjalizatora, aby zainicjować członków.

Ty może zrobić typów POD:

struct nothing_fancy_here 
{ 
    bool b; 
    int i; 
    void* p; 
}; 

nothing_fancy_here x; 
memset(&x, 0, sizeof(x)); 

Ale jeśli robisz to na this, co oznacza, że ​​jesteś w konstruktora zdefiniowanego przez użytkownika i nie kwalifikują się jako typ POD . (Chociaż jeśli wszyscy twoi członkowie to POD, może to zadziałać, o ile żadna z nich nie zawiera wartości pułapki 0, jestem pewien, że nie ma tu zastosowania żadne inne źródło niezdefiniowanych zachowań.)

+0

Czy twój typ "nic_fancy_lady" nie ma również konstruktora? Nie sądzę, że jest jakaś różnica między tym, co nazywasz typem POD, a klasą przykładów OPs ... Bez względu na to, czy wywołasz 'memset' z poziomu konstruktora, czy nie, nie ma to znaczenia. Jeśli jest w porządku w twoim przykładzie, to jest OK w OP. –

+0

@STingRay: Nie ma konstruktora. Może '// ...' jest zbyt otwarte. – GManNickG

+0

To ma konstruktora. To prawda, że ​​to nie jest operacja. Argument dotyczący tego, czy istnieje jawnie deklarowany konstruktor, jest nieistotny. Liczy się, jak już powiedziałeś, czy struktura/klasa (lub dowolny z jej typów członków) ma funkcje wirtualnego członka. Jeśli OP nie zadeklarował konstruktora i nazwał 'memset' tak jak ty, nie ma żadnej różnicy. Tak więc ostateczna odpowiedź brzmi: w podanych przykładach jest technicznie * ok * do zrobienia, ale jako ogólna praktyka, na pewno nie ... –