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 …
Initialisierungslisten sind Wrapper um const
Arrays.
unique_ptr
das 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;
}
Das Problem ist nicht der Löscher, sondern die Tatsache, dass
std::unique_ptr
ist nur verschieben und diestd::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