Adding a full C++11 feature : move constructor and move assignment operator for vector#798
Adding a full C++11 feature : move constructor and move assignment operator for vector#798jaredhoberock merged 7 commits intoNVIDIA:masterfrom gnthibault:master
Conversation
|
Thanks Thibault! After taking a quick look at the diff, it looks like there are some spurious whitespace changes included with this pull request. Would you mind reverting the whitespace changes? It makes it easier to review the actual content of the pull request without the noisy whitespace changes showing up in the diff. |
thrust/detail/vector_base.inl
Outdated
| vector_base<T,Alloc> | ||
| ::operator=(vector_base &&v) | ||
| { | ||
| //We don't check for self move assignement : undefined behaviour |
There was a problem hiding this comment.
To avoid undefined behaviour at runtime, would it be rather better to assert(this != &v).
|
Ok, thank you for your feedback, and sorry for the messy commit, it appeared that my editor (atom) corrected many end of line space, and end of file newlines... egaburov, I took into account you remark and added the self move assignment runtime assert check. Anyway, regarding this particular aspect my comment in the previous pull request was misleading, there was no undefined behaviour per se, but a behaviour that may seems weird although compliant with move semantic: It seems that performing the self assignement check in the move assignment operator is a design choice, at least I was not able to find any specific information about the expected behaviour of self move assignement in the standard: Tests are passing using my modified version of the sconscript (not commited), but I still don't know how to enable the -std=c++11 for c++11 test build properly. |
Add |
|
Here is a comment from Howard Hinnant on self-moves to standard library types: http://stackoverflow.com/questions/13127455/what-does-the-standard-library-guarantee-about-self-move-assignment |
testing/vector.cu
Outdated
| #include <limits> | ||
|
|
||
| #if __cplusplus >= 201103L | ||
| #include <utility> |
There was a problem hiding this comment.
We may as well unconditionally #include <utility>, no matter the C++ version, since the header will always exist.
Eliminating the #if guard here (and in the other files it is used) should help reduce confusion.
|
Thanks for cleaning up the diff Thibault, it's much easier to review now! |
-Make the #include <utility> non c++11 dependent -Correction of some copy/paste erros in the comments
|
Ok I modified the comments that suffered from savage copy/pasting. So I wonder if the assert check should still be part of the vector_base move assignment, it is important to notice that it would probably differs from most of the the std::vector implementation behaviour and break some valid c++ code at runtime like this one : My opinion is that it should be removed, but I am waiting for your decisions. |
|
My interpretation of Howard Hinnant's post is that the standard says that self-moves to standard library types have undefined behavior. I think that means we can use the As a bookkeeping item, we need to note this addition in the |
|
Also: there are Do we think that these vector types also require the additions? |
|
I don't have any strong feelings about adding assert there, it was a suggestion triggered by seeing undefined behaviour comment. I have no objections if you think it should be removed. |
Adding move constructor and move assignment operator to system::cuda::vector, system::omp::vector and system::tbb::vector
|
I decided to remove the assert for self move assignment, in order to mimic the behaviour of std::vector implementation on linux distributions with gcc. I added the support for move semantic in thrust::system::cpp::vector, thrust::system::omp::vector, thrust::system::tbb::vector, and thrust::system::cuda::vector. But I did not figured out if there was specific unit test that should be written for these specific implementations to be validated ? |
|
Thanks Thibault!
I don't think we have unit tests for the backend-specific vectors since they are so similar to I think this pull request is ready to merge. @egaburov, what do you think? |
|
There is a compilation failure with one of the examples on Linux: |
|
It sounds like the backend-specific vector types will need a user-provided copy assignment operator (just like Thibault, can you introduce a copy assignment operator for each of these vectors and add it to your pull request? |
…,tbb). -The eror was caused by automatic deletion of the implicit regular copy assignment operator. We just defaulted it explicitly to get the exact same default behaviour as previously. -Moved the explicit copy assignment for device vector, from c++11 only compilation to general case. This should be more consistent with what is done in the host_vector class.
|
Sorry for the multiple modifications ... To avoid an important code duplication, and to keep the current behaviour as much as possible in the regular case (no move semantic applicable), I defaulted all the copy assignment operator in the backend classes, so they are no more deleted. Now all examples and unit tests are passing, I also wrote an ultra simple test script (linux) that tests for move semantic on all backends. As suggested earlier by Jared, I also moved the regular copy assignment operator of device_vector from C++11 guard to generic case. Another option is to make both the host_vector and the device_vector homogeneous copy assignment operator=() defaulted, as they will call their parent's anyway. |
|
@gnthibault, thanks for the additional work and due diligence. Let's go ahead and implement |
|
You are welcome! unless you would like more thorough unit testing, I am ok with the current version. I think it would also be interesting to run example/tests under windows, but I haven't got any windows platform available for the moment. |
|
Thanks Thibault. What I meant was, the last change that should be applied would be to make sure that Can these |
…tion. Re-arranged methode definition order to be more consistent with the bas class .h file
|
I re-arranged some method definitions order to be more consistent with all vectors definitions. I made all definitions in the derived classes (move construction, copy construction, move assignment, move assignment) explicit, with explicit implementation. This indeed make the code somehow more "consistent" so you don't have to ask why some methods are implemented, for instance the one that are templated, or take std::vector as input, and some other are defaulted. But, for all derived classes, ie device_vector, host_vector, cpp,cuda,omp, and tbb backends, all of the implementation I wrote correspond to the default one, and therefore could have been defaulted. This would have resulted in less code to maintain in derived class, but maybe less readable code. I let you decide if the current state satisfies thrust philosophy. Thank you for your comments |
|
Thanks @gnthibault! The only eyebrow raiser I see in the current change is that the calls to I'm going to go ahead and merge this pull request and fix it up in a separate commit. Thank you very much for your patience and hard work! |
I did a very simple, yet working implementation of move semantic, that is not the default c++11 implementation.
Here are some question you may ask:
Why C++11 default implementation is not good ?
-There is not implicit default move semantic for all thrust vector class because copy constructor, copy assignment operator and destructor are already user-declared, see (http://stackoverflow.com/questions/4819936/why-no-default-move-assignment-move-constructor) for references
Why defaulted C++11 implementation is not good ?
-because it does not necessarily initialize the "void" new object with its default constructor, depending on the type of the pointer/size member it can even just make a copy.
If a copy is performed, when deleting the temporary object, weird behaviour can occur, ie, pointer or size of the object moved from can keep their old value or take random values, and we may delete either a random pointer or more probably the valid pointer that as been copied in the move operation /!.
Why so few modifications ?
-because the swap operator was already defined in vector_base
-because device_vector and host_vector does not define their own members attributes.
Why did you defined assignment operator in device_vector ?
-because it wasn't defined before, and because, defining the move assignment operator automatically makes it deleted.
Why do the unit test does not execute when I build ?
-I did not found example of how to add pure c++11 test in the scons script, so I modified it by hand, by adding
and I get the following results under linux: