简体   繁体   中英

Why defining copy constructor gives me error: cannot bind non-const lvalue reference of type 'obj&' to an rvalue of type 'obj'?

#include <iostream>
#include <vector>
#include <array>
#define Nbodies 3

class Assembly {
public:
    // initializing constructor
    Assembly(double _dataA)
        : data(_dataA), AssA(nullptr), AssB(nullptr) { }

    // double argument copy constructor
    Assembly(Assembly &A, Assembly&B)
        : AssA(&A), AssB(&B) {
        data = A.data * B.data;
    }

    // single argument copy constructor - generates errors once uncommented
/*
    Assembly(Assembly &A)
        : data(A.data), AssA(&A), AssB(&A) {
        // initialize other members of this class here
    }
*/
    double data;
private:
    // these are const pointers to non-const objects of a type Assembly
    Assembly *const AssA, *const AssB;
};

int main() {
    std::array<double, Nbodies> datas = {1.0, 2.0, 3.0};

    // Initilize first branch of the binary tree
    std::vector<Assembly> base_assembly;
    for (int i = 0; i < Nbodies; i++) {
        base_assembly.emplace_back(datas[i]);
    }

    // Binary tree assembly - MWE (for general case, I'm using nested for loop)
    Assembly AssemblyAB = Assembly(base_assembly[0], base_assembly[1]);
    Assembly AssemblyC = Assembly(base_assembly[2]);
    Assembly AssemblyS = Assembly(AssemblyAB, AssemblyC);

    std::cout << AssemblyS.data << std::endl;

    return 0;
}

I'm working on a program that generates a binary try recursively. When I have a branch with an odd number of elements, I need to "rewrite" an element to a lower branch. For this, I use a copy constructor since I need to initialize additional members of the class (I'm using the Eigen library, and some operations can not be done as a one-liner in the initialization list).

My problem arose when I defined a singe argument copy constructor. I get the following error:

.../mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h:75:7: error:

cannot bind non-const lvalue reference of type 'Assembly&' to an rvalue of type 'Assembly'

Why defining a single argument copy constructor generates such an error? Note that in the case of a two-argument copy constructor the are no errors at all.

A typical copy constructor takes const T& , or in this case const Assembly& . Since you don't have that, there is no way for standard library containers such as std::vector to copy your type, which it would need to do if it ever needs to reallocate the array (eg to make it bigger).

However, std::vector<T> where T has a noexcept move constructor will use the move constructor instead, thus avoiding the problem of not having a copy constructor.

Thus the following addition allows this to work:

Assembly(Assembly&&) noexcept = default; // generate a noexcept move constructor

Note that this will result in the newly-constructed object also pointing to the same AssA and AssB objects.

As a side note, I would recommend renaming those to AsmA and AsmB if only to deter snickering.

Edit:

At the very root, the problem is with that single parameter Assembly& constructor, which is causing the copy constructor to not be implicitly generated. The similarity to the copy constructor is also bad due to being unintuitive. Assembly thing = other; would actually call the weird Assembly& constructor when you would expect it to just copy. Thus the best answer to the problem is just to get rid of it.

Option 1: When you want that behavior, just use the 2 parameter constructor and pass the same object twice.

Option 2: Make it a tag constructor:

// the tag type we'll use to select the weird constructor
inline struct same_asm_t {} same_asm; // not sure what version of C++ you're on; if this doesn't work remove inline and define in a cpp file elsewhere

// define this as a tag constructor (take some other "tag" type as a param for overload resolution)
Assembly(Assembly &A, same_asm_t) : data(A.data), AssA(&A), AssB(&A) {}

// use it like this, where other is an instance of Assembly
Assembly thing(other, same_asm);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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