0

我已经将“调用隐式删除的复制构造函数”编译错误的问题隔离到在声明类成员时使用 ostringstream 类型。在下面的示例中,定义了示例的 Reading 类的对象的 STL 列表。在调用 push_back 时,编译器搜索复制构造函数,但编译失败,似乎是因为 Readings 的复制构造函数已被隐式删除。

当我注释掉引用payloadString的两行时,程序编译。

我在想我的问题可能是 ostringstream 是引用类型,如下所述:

https://en.cppreference.com/w/cpp/language/copy_constructor “T 有一个右值引用类型的数据成员;” 被引用为隐式删除复制构造函数的可能原因之一。

Q的。谁能确认我上述关于 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;
}
4

2 回答 2

0

感谢 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.
于 2020-07-10T06:43:37.367 回答
0

如果您不声明一个 类,则每个类都有一个隐式声明的复制构造函数,但前提是每个数据成员和继承的类型都可以复制构造。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));

如果您确实选择实现复制构造函数/赋值,那么编译器将不会为您生成移动构造函数/赋值,您必须明确告诉编译器生成它们:

Reading(Reading &&) = default;
Reading & operator=(Reading &&) = default;
于 2020-07-10T01:27:28.897 回答