为什么 class 中的 ostringstream 类型的成员会导致 "call to implicity deleted copy-constructor" 错误?
Why does a member of ostringstream type in class cause "call to implicity deleted copy-constructor" error?
我已将“调用隐式删除的复制构造函数”编译错误问题与在声明 class 的成员时使用 ostringstream 类型隔离开来。在下面的示例中,定义了示例的 Reading class 对象的 STL 列表。在调用 push_back 的地方,编译器搜索复制构造函数并且编译失败,似乎是因为 Readings 的复制构造函数已被隐式删除。
当我注释掉引用 payloadString 的两行时,程序编译通过。
我在想我的问题可能是 ostringstream 是引用类型,如此处解释:
https://en.cppreference.com/w/cpp/language/copy_constructor
“T 有一个右值引用类型的数据成员;”被引用为隐式删除复制构造函数的可能原因之一。
问。谁能确认我上面关于 ostringstream 是引用类型导致问题的假设是否正确?
我使用 ostringstream 的原因在这个人为的例子中并不明显。也许我需要找到另一种方法来处理这个字符串,但是有人可以建议一种适用于此的方法吗?
// testing a problem where ostringstream causes implicitly deleted copy constructor
//
// using ostringstream in a class definition seems to cause implicit deletion of the copy constructor
#include <iostream>
#include <sstream>
#include <list>
#include <string>
using namespace std;
class Reading {
public:
double elevation;
std::ostringstream payloadString; // using ostringstream here causes implicit deletion of the copy constructor
double speed;
// constructors and member functions
Reading(); // initialisation constructor declaration
private:
};
Reading::Reading(): // initialisation constructor definition
elevation(0.0),
payloadString("_null_null_"), // commenting out this line and the previous definition in the class makes the problem go away
speed(0.0)
{}
int main()
{
std::list<Reading> readingsList; // a list of readings
Reading fakeReading; // just initialises with dummy data
// this line is what causes the compiler to complain about implicitly deleted copy constructors
readingsList.push_back(fakeReading);
return 0;
}
每个 class 都有一个 隐式声明的复制构造函数 如果你不声明一个,但前提是每个数据成员和继承类型都可以复制构造. std::ostringstream
没有复制构造函数,因此编译器无法为 Reading
.
生成复制构造函数
您可以自己定义一个复制构造函数,如果您可以确定一种以有意义的方式构造 Reading::payloadString
的方法。例如,您可以执行以下操作:
Reading(Reading const & other) :
elevation{other.elevation},
payloadString{other.payloadString.str()},
speed{other.speed} { }
请注意,这会复制 other.payloadString
中包含的字符串值,但不会复制流的其他方面,例如其各种输出模式或输出位置。这对你的情况可能就足够了。
如果你定义了这个构造函数,你可能还想定义复制赋值操作,同样的原因不能自动生成。您可以模仿上面复制构造函数的语义:
Reading & operator=(Reading const & other) {
elevation = other.elevation;
payloadString = std::ostringstream{other.payloadString.str()};
speed = other.speed;
return *this;
}
注意std::ostringstream
可以移动,意味着编译器会自动为Reading
生成移动构造函数和移动赋值运算符。因此,您可以从 fakeReading
:
移动构造列表元素
readingsList.emplace_back(std::move(fakeReading));
如果您确实选择实现复制 constructor/assignment,那么编译器将 不会 为您生成移动 constructor/assignment,您必须明确地告诉编译器生成它们:
Reading(Reading &&) = default;
Reading & operator=(Reading &&) = default;
感谢 cdhowie 的详细而有用的回答。
我采纳了您的建议并使用 emplace_back 实现了我的示例。下面的代码现在看起来工作得很好。
// testing a problem where ostringstream causes implicitly deleted copy constructor
//
// using ostringstream in a class definition seems to cause implicit deletion of the copy constructor
#include <iostream>
#include <sstream>
#include <list>
#include <string>
using namespace std;
class Reading {
public:
double elevation;
std::ostringstream payloadString; // using ostringstream here causes implicit deletion of the copy constructor
double speed;
// constructors and member functions
Reading(); // initialisation constructor declaration
private:
};
Reading::Reading(): // initialisation constructor definition
elevation(0.0),
payloadString("_null_null_"), // commenting out this line and the previous definition in the class makes the problem go away
speed(0.0)
{}
int main()
{
std::list<Reading> readingsList; // a list of readings
Reading fakeReading1; // just initialises with dummy data
Reading fakeReading2; // just initialises with dummy data
Reading fakeReading3; // just initialises with dummy data
fakeReading1.elevation = 1.0;
fakeReading2.elevation = 2.0;
fakeReading3.elevation = 4.0;
fakeReading1.payloadString.str("reading1 payload");
fakeReading3.payloadString.str("reading3 payload");
// this line is what causes the compiler to complain about implicitly deleted copy constructors
readingsList.emplace_back(std::move(fakeReading1));
readingsList.emplace_back(std::move(fakeReading2));
readingsList.emplace_back(std::move(fakeReading3));
for (auto const &v : readingsList){
cout << "elevation = " << v.elevation << endl;
cout << "speed = " << v.speed << endl;
cout << "payloadString = " << v.payloadString.str() << endl << endl;
}
return 0;
}
它会按预期正确生成以下输出:
elevation = 1
speed = 0
payloadString = reading1 payload
elevation = 2
speed = 0
payloadString = _null_null_
elevation = 4
speed = 0
payloadString = reading3 payload
Process returned 0 (0x0) execution time : 0.023 s
Press any key to continue.
我已将“调用隐式删除的复制构造函数”编译错误问题与在声明 class 的成员时使用 ostringstream 类型隔离开来。在下面的示例中,定义了示例的 Reading class 对象的 STL 列表。在调用 push_back 的地方,编译器搜索复制构造函数并且编译失败,似乎是因为 Readings 的复制构造函数已被隐式删除。
当我注释掉引用 payloadString 的两行时,程序编译通过。
我在想我的问题可能是 ostringstream 是引用类型,如此处解释:
https://en.cppreference.com/w/cpp/language/copy_constructor “T 有一个右值引用类型的数据成员;”被引用为隐式删除复制构造函数的可能原因之一。
问。谁能确认我上面关于 ostringstream 是引用类型导致问题的假设是否正确?
我使用 ostringstream 的原因在这个人为的例子中并不明显。也许我需要找到另一种方法来处理这个字符串,但是有人可以建议一种适用于此的方法吗?
// testing a problem where ostringstream causes implicitly deleted copy constructor
//
// using ostringstream in a class definition seems to cause implicit deletion of the copy constructor
#include <iostream>
#include <sstream>
#include <list>
#include <string>
using namespace std;
class Reading {
public:
double elevation;
std::ostringstream payloadString; // using ostringstream here causes implicit deletion of the copy constructor
double speed;
// constructors and member functions
Reading(); // initialisation constructor declaration
private:
};
Reading::Reading(): // initialisation constructor definition
elevation(0.0),
payloadString("_null_null_"), // commenting out this line and the previous definition in the class makes the problem go away
speed(0.0)
{}
int main()
{
std::list<Reading> readingsList; // a list of readings
Reading fakeReading; // just initialises with dummy data
// this line is what causes the compiler to complain about implicitly deleted copy constructors
readingsList.push_back(fakeReading);
return 0;
}
每个 class 都有一个 隐式声明的复制构造函数 如果你不声明一个,但前提是每个数据成员和继承类型都可以复制构造. std::ostringstream
没有复制构造函数,因此编译器无法为 Reading
.
您可以自己定义一个复制构造函数,如果您可以确定一种以有意义的方式构造 Reading::payloadString
的方法。例如,您可以执行以下操作:
Reading(Reading const & other) :
elevation{other.elevation},
payloadString{other.payloadString.str()},
speed{other.speed} { }
请注意,这会复制 other.payloadString
中包含的字符串值,但不会复制流的其他方面,例如其各种输出模式或输出位置。这对你的情况可能就足够了。
如果你定义了这个构造函数,你可能还想定义复制赋值操作,同样的原因不能自动生成。您可以模仿上面复制构造函数的语义:
Reading & operator=(Reading const & other) {
elevation = other.elevation;
payloadString = std::ostringstream{other.payloadString.str()};
speed = other.speed;
return *this;
}
注意std::ostringstream
可以移动,意味着编译器会自动为Reading
生成移动构造函数和移动赋值运算符。因此,您可以从 fakeReading
:
readingsList.emplace_back(std::move(fakeReading));
如果您确实选择实现复制 constructor/assignment,那么编译器将 不会 为您生成移动 constructor/assignment,您必须明确地告诉编译器生成它们:
Reading(Reading &&) = default;
Reading & operator=(Reading &&) = default;
感谢 cdhowie 的详细而有用的回答。
我采纳了您的建议并使用 emplace_back 实现了我的示例。下面的代码现在看起来工作得很好。
// testing a problem where ostringstream causes implicitly deleted copy constructor
//
// using ostringstream in a class definition seems to cause implicit deletion of the copy constructor
#include <iostream>
#include <sstream>
#include <list>
#include <string>
using namespace std;
class Reading {
public:
double elevation;
std::ostringstream payloadString; // using ostringstream here causes implicit deletion of the copy constructor
double speed;
// constructors and member functions
Reading(); // initialisation constructor declaration
private:
};
Reading::Reading(): // initialisation constructor definition
elevation(0.0),
payloadString("_null_null_"), // commenting out this line and the previous definition in the class makes the problem go away
speed(0.0)
{}
int main()
{
std::list<Reading> readingsList; // a list of readings
Reading fakeReading1; // just initialises with dummy data
Reading fakeReading2; // just initialises with dummy data
Reading fakeReading3; // just initialises with dummy data
fakeReading1.elevation = 1.0;
fakeReading2.elevation = 2.0;
fakeReading3.elevation = 4.0;
fakeReading1.payloadString.str("reading1 payload");
fakeReading3.payloadString.str("reading3 payload");
// this line is what causes the compiler to complain about implicitly deleted copy constructors
readingsList.emplace_back(std::move(fakeReading1));
readingsList.emplace_back(std::move(fakeReading2));
readingsList.emplace_back(std::move(fakeReading3));
for (auto const &v : readingsList){
cout << "elevation = " << v.elevation << endl;
cout << "speed = " << v.speed << endl;
cout << "payloadString = " << v.payloadString.str() << endl << endl;
}
return 0;
}
它会按预期正确生成以下输出:
elevation = 1
speed = 0
payloadString = reading1 payload
elevation = 2
speed = 0
payloadString = _null_null_
elevation = 4
speed = 0
payloadString = reading3 payload
Process returned 0 (0x0) execution time : 0.023 s
Press any key to continue.