Opened 6 years ago
Closed 6 years ago
#12194 closed Bugs (fixed)
Copy assignment on moveable and copyable classes uses wrong type
Reported by: | Owned by: | Ion Gaztañaga | |
---|---|---|---|
Milestone: | Boost 1.61.0 | Component: | move |
Version: | Boost 1.59.0 | Severity: | Regression |
Keywords: | Cc: |
Description
A patch introduced a breaking change to classes that are copyable and movable: https://github.com/boostorg/move/commit/4f9c2b62fbdcf5995ecf50a2ecf2494048a6696d#diff-6a11d48d06dd33c1193ffb3d794787fbR252
The macro was changed so the TYPE& operator=(TYPE &t)
calls the assignement operator with a type const TYPE&
instead of const ::boost::rv<TYPE> &
This change is not described and seems to be a mistake that was not caught in the review process. As the macro BOOST_COPY_ASSIGN_REF
still expands to the original rv-type a wrong operator might get called. A minimum example:
#include <boost/move/move.hpp> #include <cassert> class Foo{ BOOST_COPYABLE_AND_MOVABLE(Foo) public: int i; explicit Foo(int val): i(val){} Foo(BOOST_RV_REF(Foo) obj): i(obj.i) {} Foo& operator=(BOOST_RV_REF(Foo) rhs){ i = rhs.i; return *this; } Foo& operator=(BOOST_COPY_ASSIGN_REF(Foo) rhs){ i = rhs.i; return *this; } template<class OTHER> Foo& operator=(const OTHER& rhs){ i = rhs.j; return *this; } }; struct Bar{ int j; explicit Bar(int val): j(val){} }; int main(){ Foo foo1(1); Foo foo2(2); Bar bar(3); assert(foo1.i == 1); assert(foo2.i == 2); assert(bar.j == 3); foo2 = foo1; assert(foo1.i == 1); assert(foo2.i == 1); foo1 = bar; assert(foo1.i == 3); return 0; }
This compiles and works fine in boost <=1.58 but fails in >=1.59 as the template version is called.
Change History (6)
comment:1 by , 6 years ago
comment:2 by , 6 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:4 by , 6 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
The patch breaks several Boost libraries (Container and Intrusive) so it's reverted:
https://github.com/boostorg/move/commit/1194a39ab3195a17c849e1d11f4305ff6727df8b
The alternative is to document this limitation with templated assignments, similarly to Issue #12307.
comment:5 by , 6 years ago
This is strange as it returns a 'const rv<...>&' which should be ok and is also documented this way.
If the other libraries can't be fixed, please document this back to 1.59 as that change was silently introduced (no release note) and changes the observed and documented behaviour:
"const rvalue and lvalues, bind to const ::boost::rv< TYPE >&"
But now it seems it is like: "const rvalue and lvalues, bind to const ::boost::rv< TYPE >& OR const TYPE&" or a mix of both depending on some unknown conditions.
This makes it very hard to use this in non-trivial/templated contexts
comment:6 by , 6 years ago
Resolution: | → fixed |
---|---|
Status: | reopened → closed |
Documented limitation and possible workaround in commit:
https://github.com/boostorg/move/commit/cfd6be4ab46223917cb79e7dd856f582df587d7d
I found during creation of a patch (https://github.com/boostorg/move/pull/9) that
BOOST_COPY_ASSIGN_REF
causes more problems. The class assignment fails also, when assigning const instances as that would also use the template function In C++11 it works perfectly though