emplace_back和移动赋值构造函数的问题

时间:2017-01-16 21:02:26

标签: c++ c++11

给出以下代码

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);
}

,我通过调用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)\
                                                                                                   ^

(不要错过右侧隐藏的错误)

我已经花了很多时间来解决这个问题,今天,我不知道这里出了什么问题。显然,代码在方法naechster_nachbar(..)中调用了一个隐含删除的类“Knoten”的移动构造函数 - 但我不知道为什么会发生这种情况以及如何防止相应的错误消息。

另一部分(大的,略显模糊的部分)可能是在函数einlesen(...)(lambda函数?)中的某个地方引起的,可能与第一部分的原因相同。

给定的代码无法独立编译或甚至完整且有意义;它的唯一目标是演示生成的错误消息。我无法进一步减小这个最小例子的大小。我们被迫使用C ++ 11(因此命令行选项是必须的)。

非常感谢提前!

2 个答案:

答案 0 :(得分:3)

Knoten Graph::naechster_Nachbar(Knoten&)按值返回,因此会尝试复制Knoten。但它不能,因为类只有一个移动构造函数而没有复制构造函数。

有趣的是,移动构造函数实际上复制了anderer中的所有数据,因此它可能只是一个复制构造函数。

答案 1 :(得分:2)

您已为Knoten和Kante指定了移动构造函数,这会删除默认的复制构造函数。理由是,如果你编写自己的移动构造函数,那么假设这个类需要一些非平凡的逻辑,所以如果为移动构造函数/赋值运算符提供了这个逻辑,那么常规版本也需要这个逻辑。

如果添加以下代码,您的代码将被编译:

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

Kante(const Kante& anderer) = default;

但我不确定默认逻辑是否适合您的课程。您还应该考虑一下,如果您真的需要自己的移动构造函数/运算符。