Den sön 28 okt. 2018 kl 11:22 skrev Elvis Stansvik <elvst...@gmail.com>: > > Den lör 27 okt. 2018 kl 22:23 skrev Thiago Macieira > <thiago.macie...@intel.com>: > > > > On Saturday, 27 October 2018 08:33:30 PDT Sérgio Martins wrote: > > > Should we instead just encourage people to make returnsQtContainer() > > > return a const container ? > > > > We should not, since the prevents move-construction from happening. You'll > > pay > > the cost of two reference counts (one up and one down). > > Though hmm, even if we'd lose move-construction, for the copy we'd get > instead, wouldn't copy elision kick in and elide it? So we wouldn't > have to pay for the ref count up/down? > > I simplified my example a little, so to recap: > > $ cat copytest.cpp > #include <iostream> > #include <vector> > > struct Foo { > Foo() { > std::cout << this << " constructed" << std::endl; > } > Foo(const Foo &) { > std::cout << this << " copy constructed" << std::endl; > } > Foo(Foo &&) { > std::cout << this << " move constructed" << std::endl; > } > ~Foo() { > std::cout << this << " destructed" << std::endl; > } > std::vector<int>::iterator begin() { > std::cout << this << " begin" << std::endl; return v.begin(); > }; > std::vector<int>::const_iterator begin() const { > std::cout << this << " begin const" << std::endl; return v.begin(); > }; > std::vector<int>::iterator end() { > std::cout << this << " end" << std::endl; return v.end(); > }; > std::vector<int>::const_iterator end() const { > std::cout << this << " end const" << std::endl; return v.end(); > }; > std::vector<int> v{1, 2, 3}; > }; > > Foo f() { > Foo foo; > return foo; > } > > const Foo constF() { > Foo foo; > return foo; > } > > template <typename T> > const T moveToConst(T &&t) > { > return std::move(t); > } > > int main(void) { > std::cout << "without moveToConst:" << std::endl; > for (auto v : f()) { } > > std::cout << std::endl; > > std::cout << "with moveToConst:" << std::endl; > for (auto v : moveToConst(f())) { } > > std::cout << std::endl; > > std::cout << "with returning const:" << std::endl; > for (auto v : constF()) { } > > std::cout << std::endl; > > std::cout << "with recommended way:" << std::endl; > const auto stuff = f(); > for (auto v : stuff) { } > > return 0; > }
I put it up on godbolt for this who want to play: https://godbolt.org/z/x6FPq_ Elvis > > Result: > > $ g++ -std=c++17 -O0 -o copytest copytest.cpp > $ ./copytest > without moveToConst: > 0x7ffcc6ac76b0 constructed > 0x7ffcc6ac76b0 begin > 0x7ffcc6ac76b0 end > 0x7ffcc6ac76b0 destructed > > with moveToConst: > 0x7ffcc6ac7710 constructed > 0x7ffcc6ac76d0 move constructed > 0x7ffcc6ac7710 destructed > 0x7ffcc6ac76d0 begin const > 0x7ffcc6ac76d0 end const > 0x7ffcc6ac76d0 destructed > > with returning const: > 0x7ffcc6ac76f0 constructed > 0x7ffcc6ac76f0 begin const > 0x7ffcc6ac76f0 end const > 0x7ffcc6ac76f0 destructed > > with recommended way: > 0x7ffcc6ac7710 constructed > 0x7ffcc6ac7710 begin const > 0x7ffcc6ac7710 end const > 0x7ffcc6ac7710 destructed > > So it looks like the copy has been elided also in the "with returning > const" case. Anyone know if this is guaranteed in C++17, or just > permitted? > > If I compile with -fno-elide-constructors to disable elision: > > $ g++ -std=c++17 -fno-elide-constructors -O0 -o copytest copytest.cpp > $ ./copytest > without moveToConst: > 0x7ffe7c107070 constructed > 0x7ffe7c1070f0 move constructed > 0x7ffe7c107070 destructed > 0x7ffe7c1070f0 begin > 0x7ffe7c1070f0 end > 0x7ffe7c1070f0 destructed > > with moveToConst: > 0x7ffe7c107070 constructed > 0x7ffe7c107150 move constructed > 0x7ffe7c107070 destructed > 0x7ffe7c107110 move constructed > 0x7ffe7c107150 destructed > 0x7ffe7c107110 begin const > 0x7ffe7c107110 end const > 0x7ffe7c107110 destructed > > with returning const: > 0x7ffe7c107070 constructed > 0x7ffe7c107130 move constructed > 0x7ffe7c107070 destructed > 0x7ffe7c107130 begin const > 0x7ffe7c107130 end const > 0x7ffe7c107130 destructed > > with recommended way: > 0x7ffe7c107070 constructed > 0x7ffe7c107150 move constructed > 0x7ffe7c107070 destructed > 0x7ffe7c107150 begin const > 0x7ffe7c107150 end const > 0x7ffe7c107150 destructed > $ > > What I find surprising here is that with the -fno-elide-constructors > flag, in the "with returning const", the move constructor *is* called. > > Didn't we just say it wouldn't, because the const rvalue wouldn't bind > to the non-const rvalue reference? > > I'm a little confused :p > > Elvis > > > > > -- > > Thiago Macieira - thiago.macieira (AT) intel.com > > Software Architect - Intel Open Source Technology Center > > > > > > > > _______________________________________________ > > Development mailing list > > Development@qt-project.org > > http://lists.qt-project.org/mailman/listinfo/development _______________________________________________ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development