Oproep naar impliciet verwijderde kopieerconstructor in LLVM

Volgens de C++11-regels worden standaard 6 dingen (default constructor, copy constructor, move constructor, copy assignment, move assignment en destructor ) gegenereerd. Volgens de tweede regel, wanneer een aangepaste kopie, verplaatsing of destructor is gedefinieerd, worden die standaardbewerkingen niet gegenereerd.
Maar in mijn code die volgt is dat niet het geval. Maar deze code kan niet worden gecompileerd met een fout

call to implicitly deleted copy constructor of 'Uni'

Als ik mijn eigen copy-constructor voor Uni schrijf, werkt alles prima. (Het is becommentarieerd in de code, gegeven ter referentie)

Alle gedachten worden zeer op prijs gesteld.

Eindelijk draai ik dit op Mac, Xcode met LLVM-compiler.

veel dank…

#include <iostream>
class A
{
public:
    A(int i) :num{i}
    {
        std::clog<< "ctor  A() num = " << num << "\n";
    }
    A( A const &aRef)
    :num{aRef.num}
    {
        std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
    }
    int value()
    {
        return num;
    }
private:
    int num;
};
class Uni
{
public:
    Uni(A* aptr) : up{aptr}
    {
        std::clog << " ctor Uni value = " << up.get()->value() << "\n";
    }
    /*Uni(Uni const &uRef)
    {
        std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
        up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
    }*/
private:
    std::unique_ptr<A> up;
};
int main(int argc, const char * argv[])
{
    Uni one{new A{10}};
    Uni two{one}; //default copy ctor is implicitly deleted. why ?
}

Antwoord 1, autoriteit 100%

C++11-regels voor het automatisch genereren van speciale leden zijn niet zo eenvoudig als je ze hebt gepost. Het belangrijkste onderscheid is dat in sommige gevallen het lid impliciet wordt aangegeven, maar gedefinieerd als verwijderd. Dat is wat er in jouw geval gebeurt.

C++11, [class.copy] 11:

Een standaard copy/move-constructor voor een klasse X wordt gedefinieerd als verwijderd (8.4.3) als X het volgende heeft:

  • een variantlid met een niet-triviale corresponderende constructor en X is een union-achtige klasse,
  • een niet-statisch gegevenslid van het klassetype M (of array daarvan) dat niet kan worden gekopieerd/verplaatst omdat de resolutie (13.3) overbelast is, zoals toegepast op M‘s corresponderende constructor, resulteert in een dubbelzinnigheid of een functie die is verwijderd of ontoegankelijk is vanuit de standaard constructor,
  • een directe of virtuele basisklasse B die niet kan worden gekopieerd/verplaatst omdat overbelastingsresolutie (13.3), zoals toegepast op de overeenkomstige constructor van B, resulteert in ambiguïteit of een functie die is verwijderd of ontoegankelijk is vanuit de standaard constructor,
  • elke directe of virtuele basisklasse of niet-statisch gegevenslid van een type met een destructor die is verwijderd of ontoegankelijk is vanuit de standaardconstructor,
  • voor de kopie-constructor, een niet-statisch gegevenslid van het referentietype rvalue, of
  • voor de move-constructor, een niet-statisch gegevenslid of directe of virtuele basisklasse met een type dat geen move-constructor heeft en niet triviaal kopieerbaar is.

(nadruk van mij)


Meer in het algemeen zijn de regels voor automatisch gegenereerde lesgroepleden:

  • Als de klasse geen door de gebruiker opgegeven constructors heeft, wordt een standaardconstructor gedeclareerd.

  • Als de klasse geen door de gebruiker opgegeven kopie-constructor heeft, wordt er een gedeclareerd.

  • Als de klasse geen van de { door de gebruiker verstrekte kopieer- of verplaatsingsconstructor, door de gebruiker verstrekte kopieer- of verplaatsingstoewijzingsoperator, door de gebruiker verstrekte destructor } heeft, wordt een verplaatsingsconstructor gedeclareerd (maar zie (*) hieronder) .

  • Als de klas geen door de gebruiker opgegeven operator voor kopieertoewijzing heeft, wordt er een gedeclareerd.

  • Als de klasse geen van { door de gebruiker verstrekte kopieer- of verplaatsingsconstructor, door de gebruiker verstrekte kopieer- of verplaatsingstoewijzingsoperator, door de gebruiker verstrekte destructor } heeft, wordt een verplaatsingstoewijzingsoperator gedeclareerd (maar zie (*) hieronder ).

  • Als de klasse geen door de gebruiker opgegeven destructor heeft, wordt er een gedeclareerd.

Elk automatisch gedeclareerd lid kan worden gedefinieerd als standaard (de standaard dingen doen) of gedefinieerd als verwijderd (als je het probeert te gebruiken, krijg je een foutmelding). De vuistregel is: “Als de standaardversie zinvol is, wordt deze gedefinieerd als standaard. Anders wordt deze gedefinieerd als verwijderd.”

In deze context betekent ‘logisch’: ‘probeert niet een verwijderde, dubbelzinnige, ontoegankelijke of anderszins illegale functie aan te roepen’. Het standaardbit dat ik in het eerste deel van dit antwoord heb geciteerd, geeft bijvoorbeeld weer wat niet “logisch” is voor kopieerconstructeurs.

Bovendien wordt een automatisch gedeclareerde kopieerconstructor of kopieertoewijzingsoperator gedefinieerd als verwijderd als de klas een door de gebruiker verstrekte verplaatsingsconstructor of verplaatsingstoewijzingsoperator heeft.

(*) Als een automatisch gedeclareerde move-constructor of move-toewijzingsoperator zou worden gedefinieerd als verwijderd, wordt deze in plaats daarvan helemaal niet gedeclareerd. Deze regel bestaat zodat het impliciet proberen om zo’n klasse te verplaatsen terugvalt op het kopiëren ervan in plaats van het genereren van een fout.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes