
hi all unfortunately i'm totally out of time now so i only write my proposal and an example forgive me for that the code #include <algorithm> template<typename type> class temporary : public type { temporary() : type() {} temporary(temporary &a) : type() { using std::swap; swap(static_cast<type&>(*this), static_cast<type&>(a)); } template<typename other> temporary(const other &a) : type(a) {} temporary &operator=(temporary &a) { using std::swap; swap(static_cast<type&>(*this), static_cast<type&>(a)); return *this; } template<typename other> temporary &operator=(const other &a) { type::operator=(a); return *this; } }; example1 temporary<huge_type> foo(const huge_type &a) {//returning temporary object temporary<huge_type> ret; //or even 'ret(a)' //doing something... return ret; } //... huge_type result; result = foo(bar); //somewhere in code only one copy operation -- assignment operator return by value copying overhead is eliminated with help of swap() example2 struct my_type { //... my_type(temporary<my_type> &a) { this->swap(a); } //... my_type &operator=(temporary<my_type> &a) { this->swap(a); return *this; } //... }; temporary<my_type> process(const my_type &item) { temporary<my_type> ret; //processing item... return ret; } //... my_type result = process(item); //somewhere in code //or result = process(item); no temporary object handling overhead at all return by value, copy-construct and assign from temporary objects for free! thank you for attention

DE wrote:
hi all
unfortunately i'm totally out of time now so i only write my proposal and an example forgive me for that
What about a good read on Named Return Value Optimization and the upcoming move features ... -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

What about a good read on Named Return Value Optimization and the upcoming move features ... afaik nrvo is not implemented in msvc80 certainly it would be nice to have such but with current standard it is very hard to implement it because it is very hard to statically analyse the code of copy constructor and assignment operator i mean either the standard would be broken or the optimized code might
on 30.10.2009 at 1:02 joel wrote : produce unexpected behavior, e.g. where you expect 2 copy constructors there is only 1 etc. i live in real world (i.e. with c++98 standard) and propose very simple yet efficient and complete (in several scope) solution while nrvo is not guaranteed (again afaik) to take place this approach will always (!) work if it is explicitly stated so i'm not familiar with upcoming move features but my guess is that it will be some nerdy metaprogramming (no offence guys) while i propose almost trivial solution which can be started using right now without even changing classes (structs) definitions -- Pavel

DE wrote:
some unbacked claims ...
Read and learn http://cpp-next.com/archive/category/value-semantics/ -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

DE wrote:
afaik nrvo is not implemented in msvc80
RVO is implemented since MSVC6, NRVO since MSVC7.
certainly it would be nice to have such but with current standard it is very hard to implement
Not really. You just have to deduce the expression you're returning is either a temporary or a local variable, which is hardly difficult for a compiler.
it because it is very hard to statically analyse the code of copy constructor and assignment operator
NRVO doesn't involve the assignment operator at all. The optimization also doesn't even require to know what the definition of the copy constructor is, so static analysis of its definition is irrelevant.
i mean either the standard would be broken or the optimized code might produce unexpected behavior, e.g. where you expect 2 copy constructors there is only 1 etc.
The standard explicitly states that the compiler is allowed to elide calls to the copy constructor in certain situations, even if the copy constructor in question has side effects. It also states the same thing for move constructors in C++0x.
while nrvo is not guaranteed (again afaik) to take place this approach will always (!) work if it is explicitly stated so
Boost.Move already provides move emulation for C++03, and moving is independent from NRVO.
i'm not familiar with upcoming move features but my guess is that it will be some nerdy metaprogramming (no offence guys) while i propose almost trivial solution which can be started using right now without even changing classes (structs) definitions
Boost.Move is actually fairly similar to what you are proposing. And no, it's not nerdy meta-programming, C++0x is simply introducing a new mechanism to distinguish rvalues from lvalues: rvalue references.

on 31.10.2009 at 17:12 Mathias Gaunard wrote :
afaik nrvo is not implemented in msvc80 RVO is implemented since MSVC6, NRVO since MSVC7. you might know better however afaik these are of very limited use
certainly it would be nice to have such but with current standard it is very hard to implement Not really. You just have to deduce the expression you're returning is either a temporary or a local variable, which is hardly difficult for a compiler. it because it is very hard to statically analyse the code of copy constructor and assignment operator NRVO doesn't involve the assignment operator at all. The optimization also doesn't even require to know what the definition of the copy constructor is, so static analysis of its definition is irrelevant. i mean that in an example like
type foo(const type &to_be_processed) { type ret; //processing return ret; } semantics of the copy constructor does matter here nrvo likely not to take place (actually it should NOT take place)
i mean either the standard would be broken or the optimized code might produce unexpected behavior, e.g. where you expect 2 copy constructors there is only 1 etc. The standard explicitly states that the compiler is allowed to elide calls to the copy constructor in certain situations, even if the copy constructor in question has side effects. It also states the same thing for move constructors in C++0x. afaik by the standard a compiler only allowed to directly construct a temporary only in case like
type bar(const other &a) { intermediate i; //??? return type(i); } //... res = bar(input);
while nrvo is not guaranteed (again afaik) to take place this approach will always (!) work if it is explicitly stated so Boost.Move already provides move emulation for C++03, and moving is independent from NRVO. i'm not familiar with upcoming move features but my guess is that it will be some nerdy metaprogramming (no offence guys) while i propose almost trivial solution which can be started using right now without even changing classes (structs) definitions Boost.Move is actually fairly similar to what you are proposing. well, to this point i still think that a temporary<type> better reflects the underlying semantics than, i guess, BOOST_RV_REF(type) (looks extremely ugly)
And no, it's not nerdy meta-programming, C++0x is simply introducing a new mechanism to distinguish rvalues from lvalues: rvalue references. i have a picture of that and you can't imagine how hard i wait for the new standard but for now i try to exploit existing tools that's why all these perversions exist
-- Pavel

AMDG DE wrote:
on 31.10.2009 at 17:12 Mathias Gaunard wrote :
NRVO doesn't involve the assignment operator at all. The optimization also doesn't even require to know what the definition of the copy constructor is, so static analysis of its definition is irrelevant.
i mean that in an example like
type foo(const type &to_be_processed) { type ret; //processing return ret; }
semantics of the copy constructor does matter here nrvo likely not to take place (actually it should NOT take place)
This is exactly the case where NRVO should happen. (NRVO stands for named return value optimization as opposed to RVO which is for temporaries) In Christ, Steven Watanabe

on 02.11.2009 at 20:52 Steven Watanabe wrote :
i mean that in an example like
type foo(const type &to_be_processed) { type ret; //processing return ret; }
semantics of the copy constructor does matter here nrvo likely not to take place (actually it should NOT take place)
This is exactly the case where NRVO should happen. (NRVO stands for named return value optimization as opposed to RVO which is for temporaries) well, then my question is: _will_ it happen?
-- Pavel

DE wrote:
Mathias Gaunard wrote:
Boost.Move is actually fairly similar to what you are proposing. well, to this point i still think that a temporary<type> better reflects the underlying semantics than, i guess, BOOST_RV_REF(type) (looks extremely ugly)
Boost.Move is really similar to what you are proposing, but it also handles the case that the compiler actually supports rvalue-references. So BOOST_RV_REF is a macro defined as: #ifdef BOOST_HAS_RVALUE_REFS #define BOOST_RV_REF(TYPE) TYPE && #else #define BOOST_RV_REF(TYPE) boost::rv< TYPE >& #endif It is true that macros always look ugly, but this is exactly the situation where you have to use a macro to abstract away unavoidable language differences. Regards, Thomas

on 02.11.2009 at 23:08 Thomas Klimpel wrote :
Boost.Move is really similar to what you are proposing, but it also handles the case that the compiler actually supports rvalue-references. So BOOST_RV_REF is a macro defined as:
#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_RV_REF(TYPE) TYPE && #else #define BOOST_RV_REF(TYPE) boost::rv< TYPE >& #endif
It is true that macros always look ugly, but this is exactly the situation where you have to use a macro to abstract away unavoidable language differences.
ok then i'm stopping panic right now i understand your point and i think that it is probably right however i'm stuck to my own opinion -- Pavel

DE wrote
on 31.10.2009 at 17:12 Mathias Gaunard wrote :
afaik nrvo is not implemented in msvc80 RVO is implemented since MSVC6, NRVO since MSVC7. you might know better however afaik these are of very limited use
They do what the name says.
i mean that in an example like
type foo(const type &to_be_processed) { type ret; //processing return ret; }
semantics of the copy constructor does matter
No, they don't.
here nrvo likely not to take place (actually it should NOT take place)
That's exactly the case where it will.
afaik by the standard a compiler only allowed to directly construct a temporary only in case like
type bar(const other &a) { intermediate i; //??? return type(i); } //... res = bar(input);
This is a bad example of RVO which doesn't actually work. There will still be a temporary here.
well, to this point i still think that a temporary<type> better reflects the underlying semantics than, i guess, BOOST_RV_REF(type) (looks extremely ugly)
The point of the macro is that it can use type&& (rvalue references) or temporary<type> depending on what is available.
i have a picture of that and you can't imagine how hard i wait for the new standard but for now i try to exploit existing tools that's why all these perversions exist
The right approach is to design systems that look that those of the future, that can use the future features when available and that fallback on emulation techniques when they're not.

on 03.11.2009 at 20:26 Mathias Gaunard wrote :
The right approach is to design systems that look that those of the future, that can use the future features when available and that fallback on emulation techniques when they're not. i almost agree however i think that until the future features are delivered one shouldn't make things depending on that features but that doesn't mean one shouldn't keep the future in mind
-- Pavel

DE wrote:
unfortunately i'm totally out of time now so i only write my proposal and an example forgive me for that
Now you will have to forgive us our cryptic answers. And I assume that you are somewhat familiar with copy elision, return value optimization, rvalues and some move-emulation libraries and move-support proposals (rvalue references).
template<typename type> class temporary : public type
This is actually an interesting semantic. I just checked and found that the proposed Boost.Move library also uses the same semantics (move.hpp:72-73: template <class T> class rv : public T ), but the older Adobe Move library doesn't use it, and the semantics of the proposed rvalue-reference is also different from this. What I like about this semantics is that for class A {...}; class B : public A {...}; the type "temporary<B>&" cannot implicitly be converted to "temporary<A>&". For the proposed rvalue-reference, the type "B&&" can implicitly be converted to "A&&", and I have the impression that this can lead to behavior even worse than slicing. Regards, Thomas

on 30.10.2009 at 12:57 Thomas Klimpel wrote :
template<typename type> class temporary : public type
This is actually an interesting semantic. I just checked and found that the proposed Boost.Move library also uses the same semantics (move.hpp:72-73: template <class T> class rv : public T ), but the older Adobe Move library doesn't use it, and the semantics of the proposed rvalue-reference is also different from this.
What I like about this semantics is that for
class A {...}; class B : public A {...};
the type "temporary<B>&" cannot implicitly be converted to "temporary<A>&". For the proposed rvalue-reference, the type "B&&" can implicitly be converted to "A&&", and I have the impression that this can lead to behavior even worse than slicing. very good point i didn't think about it
well, i'd try to rephrase this issue: for D derived from B does swap(A, B) implements the right semantics and what is that "right semantics"? but this looks like off topic so far -- Pavel

on 30.10.2009 at 12:57 Thomas Klimpel wrote :
For the proposed rvalue-reference, the type "B&&" can implicitly be converted to "A&&", and I have the impression that this can lead to behavior even worse than slicing. by the way such reasoning can really put that proposal on ice and we'll not see it in the new standard
on the other hand all responsibility can be laid on users' shoulders -- Pavel

DE wrote:
by the way such reasoning can really put that proposal on ice and we'll not see it in the new standard
on the other hand all responsibility can be laid on users' shoulders
Well, since swap itself has the same issues, there's no reason to put the proposal on ice. The point of the rvalue-references proposal is probably that rvalue-references are like normal references with slightly different rules which objects they can bind. This is easy for a compiler to implement and easy for a user to understand. What I really would like for the move-proposal is to allow implementing the move-assignment operator as a simple swap, even for vector or shared_ptr. However, it won't happen. First of all, convincing everybody that it makes sense is impossible, and on top of that another language change would be required. The language change would have to say that temporary objects that bind to a non-const rvalue-reference get destroyed directly after the function/method returns (in order to avoid a counter-example that Dave proposed). This change would be difficult to implement for a compiler and difficult for a user to understand. I guess what will happen is that most major compilers will implement rvalue-references long before they make it officially into the standard (since the standard will be ready soon, this implies that most major compilers have already implemented rvalue-references) and that the standard libraries will implement and exploit move-support at the same time. And when the next standard will be finished, it will contain rvalue-references and move-support, and it will be good enough for all practical purposes. And Scott Meyers will either have to explain how to implement a "well behaved" move-assignment operator, or explain that one has to be careful when using std::move or std::move_iterator. I guess he will have to explain both anyway :-) I just hope that there will be some agreement on what is considered to be a "well behaved" move-assignment operator. Regards, Thomas

Mathias Gaunard wrote:
Thomas Klimpel wrote:
What I really would like for the move-proposal is to allow implementing the move-assignment operator as a simple swap
Testing shows that this is suboptimal and can hurt performance significantly.
You probably want to say that implementing "a = std::move(b)" as tmp.members = a.members a.members = b.members b.members = tmp.members is significantly slower than implementing it as a.members = b.members I believe this without testing. What I'm talking about is that the move-assignment operator of the proposed boost::container::vector is implemented for good reasons as vector& operator=(BOOST_RV_REF(vector) x) { if (&x != this){ this->swap(x); x.clear(); } return *this; } and it would be nice if it would be allowed to implement it as vector& operator=(BOOST_RV_REF(vector) x) { this->swap(x); return *this; } However, I accepted that "it would be nice" won't come reality, because the good reasons are just too good (with the otherwise required language change as final word). Regards, Thomas

on 31.10.2009 at 18:37 Thomas Klimpel wrote :
What I'm talking about is that the move-assignment operator of the proposed boost::container::vector is implemented for good reasons as
vector& operator=(BOOST_RV_REF(vector) x) { if (&x != this){ this->swap(x); x.clear(); } return *this; }
and it would be nice if it would be allowed to implement it as
vector& operator=(BOOST_RV_REF(vector) x) { this->swap(x); return *this; }
However, I accepted that "it would be nice" won't come reality, because the good reasons are just too good (with the otherwise required language change as final word). good point, i second this i think there is no need for self-assignment test rather assignment (or whatever) should be implemented in a self-assignment-safe manner also there is no need to 'clear()' because the destructor will take care of whatever the object 'x' remains to be and finally i think that 'this->swap(x)' and 'x.swap(*this)' must have identical by definition effect so there is no matter what form to use
-- Pavel

Thomas Klimpel wrote:
I guess what will happen is that most major compilers will implement rvalue-references long before they make it officially into the standard (since the standard will be ready soon, this implies that most major compilers have already implemented rvalue-references) There's no need to guess. GCC, CodeGear C++Builder, MSVC++, Comeau and Clang all have implemented rvalue references already, although in some cases with early draft semantics.
Sebastian
participants (7)
-
DE
-
Dmitry Goncharov
-
joel
-
Mathias Gaunard
-
Sebastian Redl
-
Steven Watanabe
-
Thomas Klimpel