Kopie van functor en initializer_list

Ik ben een beetje in de war over wat er gebeurt als ik functoren en/of initializers kopieer. In de volgende code dacht ik dat ik de objecten de hele tijd zou kopiëren/verplaatsen maar zonder Segfaults. Ik schijn iets verkeerd te doen, maar ben er nog niet achter, wat mijn verkeerde veronderstellingen zijn. Vreemd op cppreference.com Ik kon de constructor voor initializer_list niet vinden of verplaatsen, dus ik vraag me af wat er in deze gevallen werkelijk gebeurt.

#include 
#include 
#include 
#include 

std::initializer_list> getInitializer() {
  return {
    []() -> std::string {
      return "If";
    }
  };
}

int main() {
    std::function func;
    {
        auto init = getInitializer();

        func = [init](std::string text) -> int {
            std::vector> vec(init);

            for( auto& el : vec ) {
                std::cout << el();
            }
            std::cout << text << std::endl;
            return 5;
        };
    }

    return func(" you see this - the world is all right!");
}
4
@ColeJohnson gebruiken voor wat?
toegevoegd de auteur abergmeier, de bron
Waarom voeg je een -instructie niet bovenaan toe?
toegevoegd de auteur Cole Johnson, de bron
@LCIDFire met namespace std; , zodat u niet altijd std: hoeft te typen. msdn.microsoft.com/en-us/library /aewtdfs3(v=vs.100).aspx
toegevoegd de auteur Cole Johnson, de bron
@ColeJohnson Het is geen goede gewoonte om overal "namespace std" te gebruiken, waarmee de globale naamruimte wordt verontreinigd met veel symbolen die u niet zult gebruiken. LCID: leuke vraag, het ziet ernaar uit dat de originele std :: -functies ergens worden vernietigd.
toegevoegd de auteur mfontanini, de bron

1 antwoord

Ik heb niet veel ervaring met initializer_list s, maar de standaard lijkt te suggereren dat de implementatie van een initializer_list lijkt op een paar aanwijzers naar een array. De lijst op getInitializer heeft automatische levensduur , en dat geldt ook voor de array die het ondersteunt. Uiteindelijk krijg je een paar wijzers terug naar een array die niet meer bestaat.

De relevante delen van de standaard zijn 8.5.4 [decl.init.list] items 5 en 6:

5.- An object of type std::initializer_list is constructed from an initializer list as if the implementation allocated an array of N elements of type E, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list object is constructed to refer to that array. If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.

6.- The lifetime of the array is the same as that of the initializer_list object.


Dus voor uw specifieke geval zou de implementatie ongeveer hetzelfde zijn als dit:

std::initializer_list> getInitializer() {
  std::function __a[1] = {
    []() -> std::string {
      return "If";
    }
  };
  return std::initializer_list>(__a, __a+1);
}
7
toegevoegd
Ik ben een beetje in de war. Waarom hebben ze besloten om std :: initializer_list met een geheugenarray te implementeren? Waarom niet gaan en baseren op std :: array ? Voor mij is deze klasse volkomen verbroken, omdat gewoon containergebruik niet werkt.
toegevoegd de auteur abergmeier, de bron
@ K-ballo Als je kijkt naar het aantal containers dat std :: initializer_list argumenten accepteert in hun functieaanroepen, krijg je ideeën :). Op het einde gebruik ik nu std :: vector .
toegevoegd de auteur abergmeier, de bron
@LCID Fire: Waarom gebruik je in plaats daarvan niet gewoon std :: array ?
toegevoegd de auteur K-ballo, de bron
@LCID Fire: al die functies hebben ook overbelasting met een [begin, einde) paar iterators, zo is het terug gedaan in de niet- std :: initializer_list dagen.
toegevoegd de auteur K-ballo, de bron
@LCIDFire std :: initializer_list is geen container, het is niet verbroken omdat het niet zo is ontworpen. Het probleem hier is dat je ervan uitgaat en het gebruikt voor iets waarvoor het nooit bedoeld was. Het is een magische functie waarmee containers gemakkelijk geïnitialiseerd kunnen worden, probeer het niet voor onbepaalde tijd op te slaan, gebruik het als een lid van een klasse, of behandel het als een eersteklas object bedoeld voor algemene toepasbaarheid op elke soort code.
toegevoegd de auteur Jonathan Wakely, de bron
@LCIDFire std :: array is hier niet het probleem (een implementatie is immers gratis om in feite te gebruiken). De SC heeft ervoor gekozen de levensduur van de objecten waarnaar wordt verwezen te beperken om de std :: initializer_list licht en goedkoop te kopiëren. Het heeft effectief referentiesemantiek, wat, je hebt gelijk, is ongewoon voor C ++. std :: initializer_list was niet bedoeld als een container, u zou er in plaats daarvan een moeten retourneren.
toegevoegd de auteur Luc Danton, de bron