most vexing parse (tsz. most vexing parses)
Ez a furcsa viselkedés a C++ nyelvtani szabályai miatt történik, és hibátlan szintaxis mellett is teljesen mást jelent, mint amit várnánk.
class Widget {
public:
Widget(int) {}
};
int main() {
Widget w(Widget(5)); // ← Most vexing parse!
}
Szeretnénk létrehozni egy Widget
nevű objektumot, amelyet egy másik Widget(5)
példány alapján konstruálunk.
A fordító nem objektumot lát, hanem:
Egy függvénydeklarációt
w
nevű függvényről, amely egyWidget
típusú paramétert fogad, és visszatérési típusaWidget
.
Tehát a fenti kód NEM hoz létre objektumot. Ez a most vexing parse.
A C++ nyelv erősen ambivalens a deklarációkkal kapcsolatban. Egy Type name(params)
forma lehet:
params
konstruktorparaméter)params
paraméterlista)A fordító a legszűkebb értelmezést választja: ha valami lehetséges függvényként, akkor annak fogja tekinteni.
std::vector<int> v(std::vector<int>(10)); // ⚠️ most vexing parse
A programozó azt szeretné:
Hozz létre egy
std::vector<int>
nevűv
nevű változót, amely egy 10 elemű vektorból jön létre.
A fordító így látja:
Függvény
v
, amely egystd::vector<int>
típusú paramétert vesz, és visszatérstd::vector<int>
típussal.
Nincs objektum, nincs konstrukció.
{}
):Widget w{Widget(5)};
Ez biztosan konstrukció, nem függvénydeklaráció. C++11-től kezdve ajánlott.
Widget temp(5);
Widget w(temp);
Külön lépésként elkerülhető a félreértelmezés.
auto w = Widget(5);
Itt egyértelmű, hogy w
egy objektum lesz.
std::vector v{std::vector<int>(10)};
A C++ nyelv visszafelé kompatibilis a C-vel, ahol a deklarációs szintaxis hasonló (pl. int f(int);
). A type name(args)
forma deklarációnak is jelenthető, így a szintaxis kétértelmű, és a szabvány az elemzést a deklaráció felé tolja el, ha lehetséges.
Ezért nem szintaktikai hiba – ez a szabványos viselkedés.
std::vector
, std::map
)
g++ -Wall
alatt sem mindig)
Tulajdonság | Leírás |
---|---|
Név | Most Vexing Parse |
Lényege | Kifejezés → félreértelmezett függvénydeklaráció |
Oka | Kétértelmű C++ szintaxis (type name(args)) |
Tünete | Nincs objektum, de nincs hiba |
Elkerülés módja | {} -alapú konstrukció, auto , = , külön lépések
|
Első jelentés | Barton & Nackman könyv, Scott Meyers is ír róla |
Előfordulási helyek | STL, sablonos kód, konstruktorhívások |
C++ verzióval javítható | C++11-től kezdve {} használat ajánlott
|
A most vexing parse tipikusan az a „C++-csapda”, amibe még tapasztalt programozók is beleesnek. Az egyetlen biztos módszer ellene a tudatosság és modern C++-szintaxis használata (uniform initialization, auto
, std::make_
típusú segédfüggvények).