简体   繁体   中英

Problems with emplace_back and move assignment constructors

Given the following code

test.h:

#ifndef __graph_aufbau_header__
#define __graph_aufbau_header__
#include <vector>
#include <queue>
#include <string>

using namespace std;

class Knoten {
    public:
        unsigned int nummer;
        double x_1;
        double x_2;
        unsigned int abstand;

        Knoten(unsigned int num, double x1, double x2) : nummer(num), x_1(x1), x_2(x2), abstand(-1) {};
        Knoten(Knoten&& anderer) : nummer(anderer.nummer), x_1(anderer.x_1), x_2(anderer.x_2), abstand(anderer.abstand) {};
        Knoten& operator=(Knoten&& anderer) = default;
};

class Kante {
    public:
        unsigned int quellknotennum;
        unsigned int zielknotennum;
        unsigned int gewicht;

        Kante(unsigned int qnum, unsigned int znum, unsigned int gew)
        : quellknotennum(qnum), zielknotennum(znum), gewicht(gew)
        {};

        Kante(Kante&& andere)
        : quellknotennum(andere.quellknotennum), 
        zielknotennum(andere.zielknotennum), 
        gewicht(andere.gewicht) {};

        Kante& operator=(const Kante& andere) = default;
        inline bool operator<(const Kante& kante_2){
           return this->quellknotennum < kante_2.quellknotennum;
        };
};

class Offset {
    public:
        unsigned int knoten_num;
        unsigned int kanten_num;

        Offset(unsigned int knnum, unsigned int kanum) 
        : knoten_num(knnum), kanten_num(kanum) 
        {};
        Offset(Offset&& anderer)
        : knoten_num(anderer.knoten_num), kanten_num(anderer.kanten_num) {};

        Offset& operator=(Offset& anderer) = default;
};

class Graph {
    public:
            vector<Knoten> coordList;
            vector<Kante> edgeList;
            vector<Offset> edgeOffsets;
            //vector<unsigned int> abstand;

            Graph() : coordList(), edgeList(), edgeOffsets(){};

            void knoten_einlesen(double x_1, double x_2);
            void kante_einlesen(unsigned int quellknoten, unsigned int zielknoten, unsigned int gewicht);
            void offset_einlesen(unsigned int nummer, unsigned int kante);
            void einlesen(string quelle);
            Knoten naechster_Nachbar(Knoten& knoten);
};

#endif

test.cc:

// kein iostream
#include <fstream>  // benötigt für die Deklaration eines Dateistroms
#include <iostream>
#include <string>
#include <sstream> // zum Splitten
//#include <regex>
#include <cstdlib>   // Zur Umwandlung von Strings in Doubles
#include <algorithm>  // fuer find_if()
#include <queue>
#include <vector>
#include "test.h"

using namespace std;

void Graph::knoten_einlesen(double x_1, double x_2){
    unsigned int neue_position = coordList.size();
    coordList.emplace_back(neue_position, x_1, x_2);
}

void Graph::kante_einlesen(unsigned int knoten_1, unsigned int knoten_2, unsigned int gewicht){
    edgeList.emplace_back(knoten_1, knoten_2, gewicht);
}

void Graph::offset_einlesen(unsigned int nummer, unsigned int kante){
    edgeOffsets.emplace_back(nummer, kante);
}

void Graph::einlesen(string quelle){
    ifstream datendatei(quelle);

    if (datendatei.is_open()){
        string aktuelle_zeile;

        getline(datendatei, aktuelle_zeile);
        unsigned int anzahl_knoten = stoi(aktuelle_zeile);

        getline(datendatei, aktuelle_zeile);
        unsigned int anzahl_kanten = stoi(aktuelle_zeile);

        unsigned int nummer, position;
        for(auto& knoten: coordList){
            nummer = knoten.nummer;
            auto erste_kante = find_if(edgeList.begin(), edgeList.end(), [nummer] (Kante kante)\
            {return nummer == kante.quellknotennum;});
            position = erste_kante - edgeList.begin();   // Position der ersten Kante, die mit dem Knoten verbunden ist, in edgeOffsets
            offset_einlesen(nummer, position);
        }


        datendatei.close();
    }
}

Knoten Graph::naechster_Nachbar(Knoten& knoten){
    return coordList.at(edgeList.at(edgeOffsets.at(knoten.nummer).kanten_num).zielknotennum);
}

, I'm getting the following error by calling g++ -std=gnu++11 test.cc :

test.cc: In member function 'Knoten Graph::naechster_Nachbar(Knoten&)':
test.cc:55:96: error: use of deleted function 'constexpr Knoten::Knoten(const Knoten&)'
         return coordList.at(edgeList.at(edgeOffsets.at(knoten.nummer).kanten_num).zielknotennum);
                                                                                                ^
In file included from test.cc:11:0:
test.h:10:11: note: 'constexpr Knoten::Knoten(const Knoten&)' is implicitly declared as deleted because 'Knoten' declares a move constructor or move assignment operator
     class Knoten {
           ^~~~~~
In file included from C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/stl_algobase.h:71:0,
                 from C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/char_traits.h:39,
                 from C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/ios:40,
                 from C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/istream:38,
                 from C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/fstream:38,
                 from test.cc:2:
C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/predefined_ops.h: In instantiation of 'bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<Kante*, std::vector<Kante> >; _Predicate = Graph::einlesen(std::__cxx11::string)::<lambda(Kante)>]':
C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/stl_algo.h:120:14:   required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Kante*, std::vector<Kante> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<Graph::einlesen(std::__cxx11::string)::<lambda(Kante)> >]'
C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/stl_algo.h:161:23:   required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<Kante*, std::vector<Kante> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<Graph::einlesen(std::__cxx11::string)::<lambda(Kante)> >]'
C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/stl_algo.h:3817:28:   required from '_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = __gnu_cxx::__normal_iterator<Kante*, std::vector<Kante> >; _Predicate = Graph::einlesen(std::__cxx11::string)::<lambda(Kante)>]'
test.cc:44:57:   required from here
C:/Program Files/mingw-w64/x86_64-6.2.0-win32-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/bits/predefined_ops.h:234:11: error: use of deleted function 'constexpr Kante::Kante(const Kante&)'
  { return bool(_M_pred(*__it)); }
           ^~~~~~~~~~~~~~~~~~~~
In file included from test.cc:11:0:
test.h:22:11: note: 'constexpr Kante::Kante(const Kante&)' is implicitly declared as deleted because 'Kante' declares a move constructor or move assignment operator
     class Kante {
           ^~~~~
test.cc:43:99: note:   initializing argument 1 of 'Graph::einlesen(std::__cxx11::string)::<lambda(Kante)>'
                 auto erste_kante = find_if(edgeList.begin(), edgeList.end(), [nummer] (Kante kante)\
                                                                                                   ^

(Don't miss the errors printed on the right, hidden side)

I've tried many hours to solve this problem and today, I do not have any idea what is going wrong here. Apparently, the code calls an implicitely deleted move constructor of the class "Knoten" in the method naechster_nachbar(..) - but I don't know why this happens and how I can prevent the corresponding error message.

The other part (the big, slightly obscure one) is probably caused somewhere in the function einlesen(...) (lambda function?), perhaps by the same reason like the first one.

The given code need not be able to compile standalone or be even complete and meaningful; its only goal is to demonstrate the generated error message. I was not able to further reduce the size of this minimal example. We are compelled to use C++ 11 (so the command line option is obligate).

Many thanks in advance!

Knoten Graph::naechster_Nachbar(Knoten&) returns by value, and so tries to copy the Knoten . But it cannot because the class only has a move constructor and no copy constructor.

Interestingly, the move constructor actually copies all the data from anderer , so it could just have been a copy constructor.

You have specified move constructors for Knoten and Kante, this makes default copy constructors deleted. The rationalle is that if you write your own move constructor, then it is assumed that some non trivial logic is required for this class, so if this logic is provided for a move constructor/assignment operator, then regular versions will also need this logic.

Your code will compile if you add:

Knoten(const Knoten& anderer) = default;
Knoten& operator=(const Knoten& anderer) = default;

and

Kante(const Kante& anderer) = default;

but I am not sure if default logic is sufficient for your classes. You should also think if you really need your own move constructors/operators here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM