Vektor > Initialisierungsliste verwenden

Lesezeit: 5 Minuten

Benutzer-Avatar
Chen

Ich bin auf einen Fehler gestoßen: Aufruf des implizit gelöschten Kopierkonstruktors von „std::__1::unique_ptr >“ wenn Code wie unten kompiliert wird
c++ -std=c++14 unique_ptr_vector.cpp -o main

Hier ist eine vereinfachte Version:

Header-Datei ‘my_header.h’:

#include <iostream>
#include <string>
#include <memory>
#include <vector>

class A{
public:
    A() : n(0) {}
    A(int val) : n(val) {} 
    A(const A &rhs): n(rhs.n) {}
    A(A &&rhs) : n(std::move(rhs.n)) {}
    A& operator=(const A &rhs) { n = rhs.n; return *this; }
    A& operator=(A &&rhs) { n = std::move(rhs.n); return *this; }
    ~A() {}

    void print() const { std::cout << "class A: " << n << std::endl; }
private:
    int n;
};

namespace {
    std::vector<std::unique_ptr<A>> vecA = {
        std::make_unique<A>(1),
        std::make_unique<A>(2),
        std::make_unique<A>(3),
        std::make_unique<A>(4)
    };
}

Und meine src-Datei unique_ptr_vector.cpp:

#include "my_header.h"

using namespace std;

int main()
{
    for(const auto &ptrA : vecA){
        ptrA->print();
    }
    return 0;
}

Muss ich wirklich verwenden push_back(std::make_unique<A>(<some_number>)) individuell für jede Komponente, oder was wäre ein bevorzugter Weg, um einen Container in einem Header zu füllen? Oder ist das generell eine schlechte Idee?

Ich habe Probleme wie dieses, dieses und dieses gesehen.

Ich weiß jetzt, dass die Initialisierungsliste unmöglich erscheint. aber was machen die Leute normalerweise mit container<unique_ptr>. Sollte ich einfach vermeiden, das in einem Header zu initialisieren …

  • Das Problem ist nicht der Löscher, sondern die Tatsache, dass std::unique_ptr ist nur verschieben und die std::initialiser_list Der Konstruktor kopiert die Elemente. Ich fürchte, Sie stecken mit dem Anrufen fest .push_back.

    – DeiDei

    13. Oktober 2017 um 20:00 Uhr

  • Ich habe an diese Möglichkeit gedacht, weil es für mich einfacher wäre, einen Container in einem Header zu initialisieren. Andernfalls muss ich eine andere Funktion definieren, um den Container zu füllen. Das ist in Ordnung, ich habe kein Problem mit push_back(), aber ich dachte, es gäbe einen prägnanteren Weg.

    – Chen

    13. Oktober 2017 um 20:15 Uhr

Benutzer-Avatar
Yakk – Adam Nevraumont

Initialisierungslisten sind Wrapper um const Arrays.

unique_ptrdas sind const kann nicht verschoben werden.

Wir können dies (auf vollkommen legale Weise) wie folgt umgehen:

template<class T>
struct movable_il {
  mutable T t;
  operator T() const&& { return std::move
  movable_il( T&& in ): t(std::move(in)) {}
};

template<class T, class A=std::allocator<T>>
std::vector<T,A> vector_from_il( std::initializer_list< movable_il<T> > il ) {
  std::vector<T,A> r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

Live-Beispiel.

Benutzen:

auto v = vector_from_il< std::unique_ptr<int> >({
  std::make_unique<int>(7), 
  std::make_unique<int>(3)
});

Wenn du wissen willst warum initializer Referenz-Konstantendaten auflistet, müssen Sie die Ausschussprotokolle aufspüren und lesen oder jemanden fragen, der dort war. Ich vermute, es geht um das Prinzip der geringsten Überraschung und/oder Leute mit Bugaboos über veränderliche Daten- und Ansichtstypen (wie das Umbenennen von array_view zu span).

Wenn Sie mehr als nur Vektoren wollen:

template<class C, class T=typename C::value_type>
C container_from_il( std::initializer_list< movable_il<T> > il ) {
  C r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

was noch massiert werden muss, um mit assoziativen Containern richtig zu arbeiten, da wir auch den Schlüssel verschieben wollen.

template<class VT>
struct fix_vt {
  using type=VT;
};
template<class VT>
using fix_vt_t = typename fix_vt<VT>::type;
template<class VT>
struct fix_vt<const VT>:fix_vt<VT>{};
template<class K, class V>
struct fix_vt<std::pair<K,V>>{
  using type=std::pair<
    typename std::remove_cv<K>::type,
    typename std::remove_cv<V>::type
  >;
};

template<class C, class T=fix_vt_t<typename C::value_type>>
C container_from_il( std::initializer_list< movable_il<T> > il ) {
  C r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

  • Bin gerade darauf gestoßen, genial! Irgendwelche Tipps für Karten? Was ich brauchen würde, ist genau die Übung, die dem Leser überlassen wird 😀 (“die noch massiert werden muss, um mit assoziativen Containern richtig zu arbeiten, da wir auch den Schlüssel verschieben wollen”).

    – Sergio Losilla

    30. Mai 2018 um 12:03 Uhr

  • @SergioLosilla Beim Ableiten Tmüssen Sie die entfernen const aus dem Schlüsselteil der std::pair<const K, V> das ist std::map<K,V>::value_type also wegziehen funktioniert (effizient)

    – Yakk – Adam Nevraumont

    30. Mai 2018 um 15:39 Uhr


  • Ich lerne hier viel, danke 🙂 Wenn es Ihnen nichts ausmacht, werde ich weiter fragen. Mit using iptr = std::unique_ptr<int>; Folgendes funktioniert vector_from_il<iptr>({iptr{new int{3}}, iptr{new int{5}}}); Aber das Folgende nicht, weil die Vorlagenableitung fehlschlägt (ich verwende g++ 8.1.1 mit -std=c++14): container_from_il<std::vector<iptr>>({iptr{new int{6}}, iptr{new int{9}}});

    – Sergio Losilla

    31. Mai 2018 um 15:43 Uhr

  • Ich habe eine Frage hinzugefügt, um dem nachzugehen, damit ich auch andere Leute belästigen kann 🙂 stackoverflow.com/questions/50629016/…

    – Sergio Losilla

    31. Mai 2018 um 16:39 Uhr

1012680cookie-checkVektor > Initialisierungsliste verwenden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy