Mi sono imbattuto in un codice che mi ha sconvolto. Essenzialmente si segue questo schema:C++ Costruisce l'oggetto due volte usando un nuovo comportamento non definito?
class Foo
{
public:
//default constructor
Foo(): x(0), ptr(nullptr)
{
//do nothing
}
//more interesting constructor
Foo(FooInitialiser& init): x(0), ptr(nullptr)
{
x = init.getX();
ptr = new int;
}
~Foo()
{
delete ptr;
}
private:
int x;
int* ptr;
};
void someFunction(FooInitialiser initialiser)
{
int numFoos = MAGIC_NUMBER;
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new(fooArray+ i) Foo(initialiser); //use placement new to initialise
}
//... do stuff
delete[] fooArray;
}
Questo codice è stato nella base di codice per anni e sembrerebbe non ha mai causato un problema. È ovviamente una cattiva idea dal momento che qualcuno potrebbe cambiare il costruttore predefinito per allocare non aspettandosi la seconda costruzione. Sostituire semplicemente il secondo costruttore con un metodo di inizializzazione equivalente sembrerebbe la cosa più sensata da fare. per esempio.
void Foo::initialise(FooInitialiser& init)
{
x = init.getX();
ptr = new int;
}
Anche se ancora soggetto a possibili perdite di risorse, almeno un programmatore di difesa potrebbe pensare di controllare per le assegnazioni precedenti in un metodo normale.
La mia domanda è:
sta costruendo due volte come questo comportamento in realtà non identificato/fuori legge da solo una cattiva idea standard o semplicemente? Se un comportamento indefinito puoi citare o indicarmi il posto giusto per cercare nello standard?
hai provato valgrind su questo codice? – zoska
Il problema principale che vedo è che 'Foo' non segue la regola del tre - l'operatore predefinito copy-ctor e copy-assignment-non farà la cosa giusta con' Foo :: ptr'. – cdhowie
@cdhowie Forse non dovremmo assumere il peggio del codice degli altri. Immagino che OP abbia semplicemente ritagliato il codice che non era necessario per porre la domanda. – anatolyg