template_back和move赋值构造函数存在问题

Problems with emplace_back and move assignment constructors

本文关键字:构造函数 存在 问题 赋值 move back template      更新时间:2023-10-16

给定以下代码

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(因此命令行选项是必需的)。

非常感谢!

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

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

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

如果您添加,您的代码将编译

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

Kante(const Kante& anderer) = default;

但我不确定默认逻辑对于您的类是否足够。您还应该考虑是否真的需要自己的move构造函数/操作符。

相关文章: