web-dev-qa-db-fra.com

Vecteur d'objets const donnant une erreur de compilation

J'ai déclaré ce qui suit dans mon code

vector <const A> mylist; 

J'obtiens l'erreur de compilation suivante -

new_allocator.h:75: error: `const _Tp* __gnu_cxx::new_allocator<_Tp>::address(const _Tp&) const \[with _Tp = const A]' and `_Tp* __gnu_cxx::new_allocator<_Tp>::address(_Tp&) const [with _Tp = const A]' cannot be overloaded

Mais si déclarer -

vector <A> mylist;

mon code se compile.

Const n'est pas autorisé dans ce contexte?

Je copie mon code ici pour référence à tous -

#include <iostream>
#include <vector>

using namespace std;
class A
{
public:
    A () {cout << "default constructor\n";}
    A (int i): m(i) {cout << "non-default constructor\n";}

private:
    int m;
};

int main (void)
{
    vector<const A> mylist;

    mylist.Push_back(1);

    return 0;
}
37
Satabdi

Les éléments d'un vecteur doivent être attribuables (ou, dans les versions plus récentes de la norme, mobiles). const les objets ne sont pas assignables, donc essayer de les stocker dans un vecteur échouera (ou au moins peut échouer - le code n'est pas valide, mais un compilateur est libre de l'accepter) de toute façon, s'il le souhaite, bien que la plupart des programmeurs préfèrent généralement que le code invalide soit rejeté).

Je suppose que pour le vrai pédant, si vous le vouliez assez, vous pourriez définir un type qui était assignable bien qu'il soit const, quelque chose comme ceci:

class ugly { 
    mutable int x;
public:
    ugly const &operator=(ugly const &u) const { 
        x = u.x;
        return *this;
    }
};

Je pense que vous devriez pouvoir stocker des articles de ce type dans un vector même s'ils sont const. Un test rapide de création d'un vecteur de ceux-ci réussit avec VC++. Cela a échoué avec certains compilateurs plus anciens (par exemple, a échoué avec g ++ 4.8.1), mais fonctionne avec des compilateurs raisonnablement récents (VC++ jusqu'à au moins 2015, g ++ à au moins 5.4 et clang ++ à au moins 4.0 - bien que je n'ai pas '' t essayé de retrouver la première version de chacun qui le supportait).

Pour un compilateur actuel, un type prenant en charge le déplacement d'objets const fonctionnerait probablement aussi bien. Mais, juste au cas où ce n'était pas évident: cela vous permet de modifier un objet même s'il est marqué const. C'est clairement une violation directe des attentes raisonnables de tout utilisateur, c'est donc surtout un problème, pas une solution.

35
Jerry Coffin

L'utilisation du Push_back la méthode est le problème. emplace_back compilera. Une autre alternative (en fonction de l'ensemble de la situation que vous ne décrivez pas ici) serait d'utiliser un vector<A const&> si les éléments insérés ont une vie en dehors du vecteur. Les éléments d'un vecteur n'ont pas besoin d'être assignables, mais lorsqu'ils ne le sont pas, certaines fonctions membres et certains algorithmes ne peuvent pas être utilisés.

Explication:

Push_back est supposé d'abord construire par défaut un A dans le vecteur, puis attribuer (en utilisant la construction de copie) la référence donnée. Cela rompt votre qualification const, donc ne compile pas.

emplace_back utilise le "transfert parfait" pour invoquer le constructeur réel directement en place.

11
lip