Ich habe herausgefunden, dass es möglich ist, die Mitgliedsvariablen mit einem Konstruktorargument mit demselben Namen wie im folgenden Beispiel zu initialisieren.
#include <cstdio>
#include <vector>
class Blah {
std::vector<int> vec;
public:
Blah(std::vector<int> vec): vec(vec)
{}
void printVec() {
for(unsigned int i=0; i<vec.size(); i++)
printf("%i ", vec.at(i));
printf("\n");
}
};
int main() {
std::vector<int> myVector(3);
myVector.at(0) = 1;
myVector.at(1) = 2;
myVector.at(2) = 3;
Blah blah(myVector);
blah.printVec();
return 0;
}
g ++ 4.4 mit den Argumenten -Wall -Wextra -pedantic
gibt keine Warnung aus und funktioniert korrekt. Es funktioniert auch mit clang ++. Ich frage mich, was der C ++ - Standard dazu sagt. Ist es legal und garantiert, dass es immer funktioniert?
Antworten:
Ja. Das ist völlig legal. Vollständig standardkonform.
Blah(std::vector<int> vec): vec(vec){} ^ ^ | | | this is the argument to the constructor this is your member data
Da Sie im Standard nach der Referenz gefragt haben, finden Sie hier ein Beispiel.
§12.6.2 / 7
[Example: class X { int a; int b; int i; int j; public: const int& r; X(int i): r(a), b(i), i(i), j(this->i) {} //^^^^ note this (added by Nawaz) };
Wie Sie sehen können, gibt es im obigen Beispiel noch weitere interessante Dinge zu beachten und den Kommentar aus dem Standard selbst.
Übrigens, als Randnotiz, warum akzeptieren Sie den Parameter nicht als konstante Referenz:
Blah(const std::vector<int> & vec): vec(vec) {} ^^^^const ^reference
Es wird eine unnötige Kopie des ursprünglichen Vektorobjekts vermieden.
quelle
Blah(std::vector<int> vec) : vec(std::move(vec)){}
. Sie können dies in C ++ 03 folgendermaßen simulieren :Blah(std::vector<int> vecSrc) { std::swap(vec, vecSrc); }
.Es funktioniert garantiert immer (ich benutze es ziemlich oft). Der Compiler weiß, dass die Initialisierungsliste die Form hat:
member(value)
und weiß daher, dass der erstevec
invec(vec)
ein Mitglied sein muss. Für das Argument zum Initialisieren des Elements können nun beide Elemente, Argumente für den Konstruktor und andere Symbole verwendet werden, wie in jedem Ausdruck, der im Konstruktor vorhanden wäre. Zu diesem Zeitpunkt werden die regulären Suchregeln angewendet, und das Argumentvec
verbirgt das Mitgliedvec
.Abschnitt 12.6.2 des Standards befasst sich mit der Initialisierung und erläutert den Prozess mit Absatz 2, der sich mit der Suche nach dem Mitglied befasst, und Absatz 7 mit der Suche nach dem Argument.
class X { int a; int b; int i; int j; public: const int& r; X(int i): r(a), b(i), i(i), j(this->i) {} };
quelle
Ein zusätzliches Gegenargument oder vielleicht nur etwas, das Sie beachten sollten, ist die Situation, in der die Verschiebungskonstruktion verwendet wird, um die Elementvariable zu initialisieren.
Wenn die Mitgliedsvariable im Hauptteil des Konstruktors verwendet werden muss, muss die Mitgliedsvariable über diesen Zeiger explizit referenziert werden, andernfalls wird die verschobene Variable verwendet, die sich in einem undefinierten Zustand befindet.
template<typename B> class A { public: A(B&& b): b(std::forward(b)) { this->b.test(); // Correct b.test(); // Undefined behavior } private: B b; };
quelle
Wie andere bereits geantwortet haben: Ja, das ist legal. Und ja, dies wird durch den Standard garantiert, um zu funktionieren.
Und ich finde es jedes Mal schrecklich, wenn ich es sehe, und zwinge mich zu pausieren: "
vec(vec)
? WTF? Ah ja,vec
ist eine Mitgliedsvariable ..."Dies ist einer der Gründe, warum viele, einschließlich ich, gerne eine Namenskonvention verwenden, die deutlich macht, dass eine Mitgliedsvariable eine Mitgliedsvariable ist. Zu den Konventionen, die ich gesehen habe, gehört das Hinzufügen eines Unterstrichsuffixes (
vec_
) oder einesm_
Präfixes (m_vec
). Dann lautet der Initialisierer:vec_(vec)
/m_vec(vec)
, was ein Kinderspiel ist.quelle