12 Stimmen

Verwendet std::vector den Zuweisungsoperator seines Werttyps, um Elemente zurückzuschieben?

Wenn ja, warum? Warum wird nicht der Kopierkonstruktor des Werttyps verwendet?

Ich erhalte den folgenden Fehler:

/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc: In member functio
n `ClassWithoutAss& ClassWithoutAss::operator=(const ClassWithoutAss&)':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc:238:   instantiate
d from `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterato
r<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
ClassWithoutAss, _Alloc = std::allocator<ClassWithoutAss>]'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_vector.h:564:   instantia
ted from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Class
WithoutAss, _Alloc = std::allocator<ClassWithoutAss>]'
main.cpp:13:   instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc:238: error: non-st
atic const member `const int ClassWithoutAss::mem', can't use default assignment
 operator

Ausführen von g++ main.cpp mit dem folgenden Code:

/*
 * ClassWithoutAss.h
 *
 */

#ifndef CLASSWITHOUTASS_H_
#define CLASSWITHOUTASS_H_

class ClassWithoutAss
{

public:
    const int mem;
    ClassWithoutAss(int mem):mem(mem){}
    ClassWithoutAss(const ClassWithoutAss& tobeCopied):mem(tobeCopied.mem){}
    ~ClassWithoutAss(){}

};

#endif /* CLASSWITHOUTASS_H_ */

/*
 * main.cpp
 *
 */

#include "ClassWithoutAss.h"
#include <vector>

int main()
{
    std::vector<ClassWithoutAss> vec;
    ClassWithoutAss classWithoutAss(1);
    (vec.push_back)(classWithoutAss);

    return 0;
}

16 Stimmen

+1 wenn auch nur für ClassWithoutAss .

2 Stimmen

Warum klammern Sie die vec.push_back ... es wird keine Probleme verursachen, aber scheint ein bisschen unnötig ...

1 Stimmen

Ist das ein "Esel" im Sinne von "Esel"?

13voto

GManNickG Punkte 476445

Der C++03-Standard besagt, dass Elemente kopierfähig und kopierzuweisbar sein müssen, um in einem Standardcontainer verwendet werden zu können. Es steht einer Implementierung also frei, das zu verwenden, was sie will.

In C++0x werden diese Anforderungen pro Operation gestellt. (Im Allgemeinen müssen Elemente move-constructible und move-assignable sein).

Um das zu erreichen, was Sie wollen, sollten Sie einen intelligenten Zeiger wie shared_ptr (entweder von Boost, TR1 oder C++0x), und deaktivieren Sie die Kopierbarkeit vollständig:

class ClassWithoutAss
{
public:
    const int mem;

    ClassWithoutAss(int mem):mem(mem){}
    // don't explicitly declare empty destructors

private:
    ClassWithoutAss(const ClassWithoutAss&); // not defined
    ClassWithoutAss& operator=(const ClassWithoutAss&); // not defined
};

typedef shared_ptr<ClassWithoutAss> ptr_type;

std::vector<ptr_type> vec;
vec.push_back(ptr_type(new ClassWithoutAss(1)));

Zeiger können problemlos kopiert werden, und der intelligente Zeiger sorgt dafür, dass keine Lecks entstehen. In C++0x können Sie dies am besten mit einem std::unique_ptr und nutzt dabei die Vorteile der Zugsemantik. (Man braucht eigentlich keine gemeinsame Semantik, aber in C++03 ist es so am einfachsten).

0 Stimmen

Ich glaube Ihnen, aber können Sie mir erklären, warum ich Zeiger verwenden soll, anstatt meine eigenen Operationen zu definieren? Schnellere Push_backs? Damit ich meine Zeit nicht mit der Definition von Operationen vergeude? Ich werde mich mit der Semantik von move/share beschäftigen müssen. Danke GMan. Ich habe diese Probleme nur mit deiner Hilfe ;)

0 Stimmen

@drenami: Wie meinen Sie das? Ich habe Zeiger verwendet, weil Sie Ihre Klasse im Container haben wollen, aber Sie können es nicht direkt tun. Eine Abstraktion über das ist ein Zeiger auf Ihre Klasse, anstatt die Klasse selbst. (Und die intelligente Zeiger nur um Lecks zu verhindern.)

0 Stimmen

Aber ich könnte es, wenn ich einen Zuweisungsoperator definieren würde, richtig? Meine Frage ist also Pro/Cons der beiden Entwürfe - einer ohne Zuweisung/Verwendung von Zeigern, einer mit definierter Zuweisung. Beide sind Optionen, weil ich ClassWithAss schreiben kann.

5voto

Martin York Punkte 245363

Das Problem dabei ist, dass die Typen in einem Container zuweisbar sein müssen.

Da Sie keinen Zuweisungsoperator für Ihre Klasse definieren, wird der Compiler einen für Sie erzeugen. Der Standard-Zuweisungsoperator sieht wie folgt aus:

ClassWithoutAss& operator=(ClassWithoutAss const& rhs)
{
    mem = copy.mem;
    return *this;
}
// The compiler generated assignment operator will copy all members
// using that members assignment operator.

In den meisten Situationen würde dies funktionieren. Aber das Mitglied mem ist eine Konstante und daher nicht zuweisbar. Daher wird die Kompilierung fehlschlagen, wenn sie versucht, den Zuweisungsoperator zu erzeugen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X