简体   繁体   English

emplace_back和move分配构造函数存在问题

[英]Problems with emplace_back and move assignment constructors

Given the following code 给出以下代码

test.h: 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: 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 : ,我通过调用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. 显然,代码在方法naechster_nachbar(..)中调用了一个隐式删除的类“ Knoten”的move构造函数-但我不知道为什么会这样以及如何防止出现相应的错误消息。

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. 另一部分(较大的部分,稍微模糊)可能是在函数einlesen(...)(lambda函数?)中的某处引起的,可能是与第一个部分相同的原因引起的。

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). 我们被迫使用C ++ 11(因此必须使用命令行选项)。

Many thanks in advance! 提前谢谢了!

Knoten Graph::naechster_Nachbar(Knoten&) returns by value, and so tries to copy the Knoten . Knoten Graph::naechster_Nachbar(Knoten&)按值返回,因此尝试复制Knoten But it cannot because the class only has a move constructor and no copy constructor. 但这不能,因为该类仅具有move构造函数而没有copy构造函数。

Interestingly, the move constructor actually copies all the data from anderer , so it could just have been a copy constructor. 有趣的是,move构造函数实际上是从anderer复制所有数据的,因此它可能只是一个复制构造函数。

You have specified move constructors for Knoten and Kante, this makes default copy constructors deleted. 您已为Knoten和Kante指定了移动构造函数,这使默认副本构造函数被删除。 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. 基本原理是,如果您编写自己的move构造函数,则假定此类需要一些非平凡的逻辑,因此,如果为move构造函数/赋值运算符提供了此逻辑,则常规版本也将需要此逻辑。

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. 您还应该考虑是否真的需要自己的移动构造函数/运算符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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