2010-09-02 8 views
1

Je souhaite créer un tableau dynamique de foo, le nombre d'éléments étant x. Les arguments y et z doivent être passés au constructeur de l'objet foo. J'espérais faire quelque chose de similaire à:Initialisation de tableau dynamique

Foo* bar = new Foo(y, z)[x]; 

Cependant qui a produit l'erreur du compilateur suivant:

error: expected `;' before '[' token 

Alors après avoir parlé avec un ami expérimenté, il m'a donné ce qu'il a admis était un paresseux manière de le faire, mais cela fonctionne. Je me demandais, y a-t-il une meilleure/bonne façon?

Foo* bar = (Foo*) new int[x]; 
for (int i = 0; i < x; i++) { 
    bar[i] = Foo(y, z); 
} 
+6

Vous et votre ami devriez obtenir un [bon livre] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) pour avoir une bonne base de compréhension. Je veux dire que le deuxième bloc de code est juste faux, pourquoi allouer 'int' et ensuite lancer' foo'? C'est presque certainement un comportement indéfini. – GManNickG

Répondre

11

« Je veux faire un tableau dynamique » Donc, utiliser un std::vector, il existe pour une raison.

std::vector<foo> bar(x, foo(y, z)); 

Cela crée un tableau dynamique avec x éléments initialisés à foo(y, z).


fait ci-dessus Le copies du second paramètre, x fois. Si vous voulez générer valeurs pour le vector, utilisez generate_n:

std::vector<double> weights; 
std::generate_n(std::back_inserter(weights), x, ...); 

Vous remplacez ... avec une fonction ou foncteur appeler, qui retourne une valeur. En général, vous faites un foncteur:

struct generate_weight 
{ 
    double operator()() const 
    { 
     return random(1e-3); 
    } 
}; 

Donner:

std::generate_n(std::back_inserter(weights), x, generate_weight()); 

Si votre compilateur prend en charge C++ 0x, vous pouvez profiter de lambda de. Ceux-ci font la même chose, sauf qu'ils gardent le code concis et localisé:

std::generate_n(std::back_inserter(weights), x, 
       [](){ return random(1e-3); }); 
+0

Alors que cela fonctionne très bien, dans cet exemple, il renvoie le même nombre pour tous les éléments du tableau: std :: vector poids (x, aléatoire (1e-3)); – dcousens

+0

@Daniel: En effet, il l'initialise à 'x' copies de' foo (y, z) '. Votre question n'a rien dit d'autre; poser de vraies questions pour obtenir de vraies réponses. J'ai mis à jour ma réponse. – GManNickG

+0

Je cherchais juste à voir si c'était le comportement attendu, n'ayant aucune expérience avec STL avant cela. J'ai utilisé le hasard (1e-3) comme exemple. Merci pour la réponse étendue. – dcousens

1

Si vous souhaitez initialiser chaque élément à la même valeur, alors faites comme GMan suggéré ci-dessus:

std::vector<foo> bar(x, foo(y, z)); 

Vous allez avoir un vecteur d'éléments X, chacun avec le même foo (y, z);

Si vous voulez une valeur unique pour chacun des foos, vous devrez l'initialiser en boucle. un exemple simple de comment est:

std::vector<foo> bar; 

    for (int i = 0; i < x; ++i) 
    { 
     // initialize X foos with different values for each foo. 
     bar.push_back(foo(i, random(i))); 
    } 
0

Si vous insistez pour ne pas utiliser std au moins le faire correctement. Ce n'est pas sûr et a de gros problèmes d'alignement.

size_t x = 10; 
foo * bar= static_cast<foo*> (::operator new (sizeof(foo)* x)); 
for (size_t i=0; i<x; ++i) 
{ 
    new (&bar[i]) foo (1,1); 
} 

::operator delete (bar); 
+1

Il n'y a pas de problèmes d'alignement ici, 'operator new' renvoie un bloc de mémoire aligné au maximum. – GManNickG

+0

@GMan - Je crains que cela n'ignore pas l'alignement de foo. –

+1

Encore une fois, il n'y a aucun problème d'alignement. §3.7.3.1/2: "... Le pointeur retourné doit être aligné de manière à pouvoir être converti en un pointeur de tout type d'objet complet puis utilisé pour accéder à l'objet ou au tableau dans le stockage alloué ..." – GManNickG

1

Tout d'abord, le seul initialiseur vous pouvez utiliser dans le tableau new-expressions est (). Donc, ce sont vous seules options si vous voulez utiliser la nouvelle expression

foo *bar = new foo[x]; // 1. no initializer 
foo *bar = new foo[x](); // 2. `()` initializer 

Selon la façon dont foo est défini, ces deux pourraient se comporter de façon identique ou différente.Deuxièmement, puisque vous ne pouvez pas passer les arguments du constructeur (y,z) dans new-expression, vous devez construire votre tableau par défaut (comme indiqué ci-dessus), puis utiliser l'affectation pour donner à vos éléments de tableau des valeurs spécifiques. Pour cela, votre foo doit être configurable par défaut et peut être affecté à la copie. Le code ressemble beaucoup à ce que votre «ami expérimenté» a suggéré, mais avec les types appropriés (au lieu de int). Ce que vous avez maintenant est inutile (d'où vient ce int?). Vous avez probablement mal compris votre ami expérimenté. Voici comment il est censé regarder

foo *bar = new foo[x]; 
for (int i = 0; i < x; i++) 
    bar[i] = foo(y,z); 

En troisième lieu, dans votre cas particulier std::vector fera la même chose d'une manière beaucoup plus élégante.

+0

C'était mon code original, mais je devrais faire un constructeur pour ne gérer aucun argument (comme vous l'avez dit, 'constructible par défaut'?) En utilisant "foo * bar = new foo [x];". Et puis ré-initiez-les tous comme vous l'avez fait. – dcousens