<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Want Speed? Pass by&#160;Value.</title>
	<atom:link href="http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/feed/" rel="self" type="application/rss+xml" />
	<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/</link>
	<description>The next generation of C++</description>
	<lastBuildDate>Mon, 30 Apr 2012 15:07:48 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
	<item>
		<title>By: Howard Hinnant</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1925</link>
		<dc:creator>Howard Hinnant</dc:creator>
		<pubDate>Mon, 02 Apr 2012 20:42:49 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1925</guid>
		<description>&lt;p&gt;That sounds right.&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>That sounds right.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Andrea</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1924</link>
		<dc:creator>Andrea</dc:creator>
		<pubDate>Mon, 02 Apr 2012 20:34:51 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1924</guid>
		<description>&lt;p&gt;Howard, thanks for your helpful reply. 
I think I&#039;m getting hold of it now. Can you just confirm my understanding is right when I say that:
When using vectors of object that have &quot;external&quot; resources (i.e. allocate memory on the heap as it is the case for strings), going through the route of invoking their constructor (as when doing ::new(end_) T(v[i]) in the copy constructor loop used when -DUSE_SWAP_ASSIGNMENT) makes you incur in the penalty of allocations even if those are placement news. Instead, the &lt;em&gt;p=&lt;/em&gt;q assignments in the plain old assignment operator&#039;s loop can re-use the already allocated memory on the destination (in particular when as in this case, the destination is a longer string) and make this approach more efficient.
As you suggested, using vectors of int (or I think more generally PODs/aggregate objects) levels out the difference of the two approaches because that extra price during the placement new has not to be payed.&lt;/p&gt;

&lt;p&gt;Andrea&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>Howard, thanks for your helpful reply. 
I think I&#8217;m getting hold of it now. Can you just confirm my understanding is right when I say that:
When using vectors of object that have &#8220;external&#8221; resources (i.e. allocate memory on the heap as it is the case for strings), going through the route of invoking their constructor (as when doing ::new(end_) T(v[i]) in the copy constructor loop used when -DUSE_SWAP_ASSIGNMENT) makes you incur in the penalty of allocations even if those are placement news. Instead, the <em>p=</em>q assignments in the plain old assignment operator&#8217;s loop can re-use the already allocated memory on the destination (in particular when as in this case, the destination is a longer string) and make this approach more efficient.
As you suggested, using vectors of int (or I think more generally PODs/aggregate objects) levels out the difference of the two approaches because that extra price during the placement new has not to be payed.</p>

<p>Andrea</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Howard Hinnant</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1923</link>
		<dc:creator>Howard Hinnant</dc:creator>
		<pubDate>Fri, 30 Mar 2012 19:41:05 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1923</guid>
		<description>&lt;p&gt;Think of it this way:  the most efficient way to recycle something is to re-use it.  The copy assignment operator can sometimes re-use memory, instead of deallocating it and then allocating more.  That is what is happening in this example.  One way deallocates memory just to turn around and allocate it back.  The other way holds on to its memory and re-uses it for the new value.  The optimization is to simply avoid calling new/delete as much as you can.&lt;/p&gt;

&lt;p&gt;I imagine the difference you&#039;re seeing with gcc is that they are using a ref-counted string.  Try the experiment again, but using MyVector&lt;std::vector&lt;int&gt;&gt; instead.&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>Think of it this way:  the most efficient way to recycle something is to re-use it.  The copy assignment operator can sometimes re-use memory, instead of deallocating it and then allocating more.  That is what is happening in this example.  One way deallocates memory just to turn around and allocate it back.  The other way holds on to its memory and re-uses it for the new value.  The optimization is to simply avoid calling new/delete as much as you can.</p>

<p>I imagine the difference you&#8217;re seeing with gcc is that they are using a ref-counted string.  Try the experiment again, but using MyVector&lt;std::vector&lt;int&gt;&gt; instead.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Andrea</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1922</link>
		<dc:creator>Andrea</dc:creator>
		<pubDate>Thu, 29 Mar 2012 16:16:50 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1922</guid>
		<description>&lt;p&gt;Wow! Tried to understand what&#039;s going on here...
Am I right in assuming the difference is in the 
::new(end_) T(v[i]) 
copy construction loop in cctor (used when -DUSE_SWAP_ASSIGNMENT) vs the
*p = *q 
assignment loop when using &quot;normal&quot; MyVector&amp; operator=(const MyVector &amp;) ???
But then why such a difference? There&#039;s a placement new up there (i.e. not real memory allocations, only string&#039;s cctor invocation), how can it be that worse than an assignment? I&#039;m sure I&#039;m missing something...
Also, testing on a mac with latest clang from trunk and gcc-4.7 built from sources, I can&#039;t see that timing difference when compiling with g++ -std=c+11. I.e., both old and swap-based assignments time almost the same as clang&#039;s best case. Is the different size of std::string (8 bytes in gnu&#039;s libstdc++ vs 24 bytes in clang&#039;s libc++) the cause of gcc&#039;s insensitivity to the kind of assignment used?&lt;/p&gt;

&lt;p&gt;Andrea&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>Wow! Tried to understand what&#8217;s going on here&#8230;
Am I right in assuming the difference is in the 
::new(end_) T(v[i]) 
copy construction loop in cctor (used when -DUSE_SWAP_ASSIGNMENT) vs the
*p = *q 
assignment loop when using &#8220;normal&#8221; MyVector&amp; operator=(const MyVector &amp;) ???
But then why such a difference? There&#8217;s a placement new up there (i.e. not real memory allocations, only string&#8217;s cctor invocation), how can it be that worse than an assignment? I&#8217;m sure I&#8217;m missing something&#8230;
Also, testing on a mac with latest clang from trunk and gcc-4.7 built from sources, I can&#8217;t see that timing difference when compiling with g++ -std=c+11. I.e., both old and swap-based assignments time almost the same as clang&#8217;s best case. Is the different size of std::string (8 bytes in gnu&#8217;s libstdc++ vs 24 bytes in clang&#8217;s libc++) the cause of gcc&#8217;s insensitivity to the kind of assignment used?</p>

<p>Andrea</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: rhalbersma</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1905</link>
		<dc:creator>rhalbersma</dc:creator>
		<pubDate>Mon, 05 Mar 2012 07:28:05 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1905</guid>
		<description>&lt;p&gt;Hi Howard,&lt;/p&gt;

&lt;p&gt;Thanks for your comment. I make an upfront reservation for the the move vector&#039;s capacity, so passing the pointer around would minimize the number of heap allocations:&lt;/p&gt;

&lt;pre&gt;        std::vector&lt;Move&gt; generate&#040;const Position&amp; p&#041;
        &#123;
            std::vector&lt;Move&gt; moves;
            moves.reserve&#040;32&#041;;
&#160;
            generate&lt;King&gt;&#040;p, moves&#041;;
            .... 
&#160;
            return moves;
        &#125;&lt;/pre&gt;

&lt;p&gt;One more question, though: would this still apply if I would use your stack allocator? So with&lt;/p&gt;

&lt;pre&gt;        std::vector&lt;Move, stack_alloc&lt;Move, 32&gt; &gt; moves;&lt;/pre&gt;

&lt;p&gt;wouldn&#039;t that make the &quot;+&quot; notation more viable?&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>Hi Howard,</p>

<p>Thanks for your comment. I make an upfront reservation for the the move vector&#8217;s capacity, so passing the pointer around would minimize the number of heap allocations:</p>

<pre>        std::vector&lt;Move&gt; generate&#040;const Position&amp; p&#041;
        &#123;
            std::vector&lt;Move&gt; moves;
            moves.reserve&#040;32&#041;;
&nbsp;
            generate&lt;King&gt;&#040;p, moves&#041;;
            .... 
&nbsp;
            return moves;
        &#125;</pre>

<p>One more question, though: would this still apply if I would use your stack allocator? So with</p>

<pre>        std::vector&lt;Move, stack_alloc&lt;Move, 32&gt; &gt; moves;</pre>

<p>wouldn&#8217;t that make the &#8220;+&#8221; notation more viable?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Matthias Vallentin</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1904</link>
		<dc:creator>Matthias Vallentin</dc:creator>
		<pubDate>Tue, 28 Feb 2012 06:26:04 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1904</guid>
		<description>&lt;p&gt;Thanks for posting the example, that your point in the previous comment clear.&lt;/p&gt;

&lt;pre&gt;Matthias&lt;/pre&gt;
</description>
		<content:encoded><![CDATA[<p>Thanks for posting the example, that your point in the previous comment clear.</p>

<pre>Matthias</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Howard Hinnant</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1903</link>
		<dc:creator>Howard Hinnant</dc:creator>
		<pubDate>Mon, 27 Feb 2012 00:04:30 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1903</guid>
		<description>&lt;p&gt;Your solution is fine as far as move semantics goes.  A reasonable rewrite is to replace all 4 of your signatures with just:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+(std::vector&lt;T&gt; lhs, const std::vector&lt;T&gt;&amp; rhs)
{
        lhs.insert(lhs.end(), rhs.begin(), rhs.end());
        return lhs;
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;That being said, I would be tempted to just do the following:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
std::vector&lt;Move&gt;
generate(const Position&amp; p)
{
    std::vector&lt;Move&gt; moves;
    generate&lt;King&gt;(p, moves);
    generate&lt;Queen&gt;(p, moves);
    generate&lt;Rook&gt;(p, moves);
    generate&lt;Bishop&gt;(p, moves);
    generate&lt;Knight&gt;(p, moves);
    generate&lt;Pawn&gt;(p, moves);
    return moves;
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This isn&#039;t quite as &quot;cute&quot; but is perfectly efficient.  And this also comes with a caveat.  If in the original code the client is calling this over and over as in:&lt;/p&gt;

&lt;pre&gt;
std::vector&lt;Moves&gt; moves;
while (...)
{
    // ...
    moves.clear();
    generate(p, moves);
    // ...
}
&lt;/pre&gt;

&lt;p&gt;Then you might consider leaving your code as is.  Count trips to the heap.  Whatever minimizes that count is the best solution.  Don&#039;t throw away vector capacity to then just allocate it back.  If you can reuse capacity, doing so is always a win.  If &lt;code&gt;moves&lt;/code&gt; is likely to hold capacity prior to the call to &lt;code&gt;generate&lt;/code&gt; then attempt to take advantage of it.&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>Your solution is fine as far as move semantics goes.  A reasonable rewrite is to replace all 4 of your signatures with just:</p>

<blockquote><pre>
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+(std::vector&lt;T&gt; lhs, const std::vector&lt;T&gt;&amp; rhs)
{
        lhs.insert(lhs.end(), rhs.begin(), rhs.end());
        return lhs;
}
</pre></blockquote>

<p>That being said, I would be tempted to just do the following:</p>

<blockquote><pre>
std::vector&lt;Move&gt;
generate(const Position&amp; p)
{
    std::vector&lt;Move&gt; moves;
    generate&lt;King&gt;(p, moves);
    generate&lt;Queen&gt;(p, moves);
    generate&lt;Rook&gt;(p, moves);
    generate&lt;Bishop&gt;(p, moves);
    generate&lt;Knight&gt;(p, moves);
    generate&lt;Pawn&gt;(p, moves);
    return moves;
}
</pre></blockquote>

<p>This isn&#8217;t quite as &#8220;cute&#8221; but is perfectly efficient.  And this also comes with a caveat.  If in the original code the client is calling this over and over as in:</p>

<pre>
std::vector&lt;Moves&gt; moves;
while (...)
{
    // ...
    moves.clear();
    generate(p, moves);
    // ...
}
</pre>

<p>Then you might consider leaving your code as is.  Count trips to the heap.  Whatever minimizes that count is the best solution.  Don&#8217;t throw away vector capacity to then just allocate it back.  If you can reuse capacity, doing so is always a win.  If <code>moves</code> is likely to hold capacity prior to the call to <code>generate</code> then attempt to take advantage of it.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Howard Hinnant</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1902</link>
		<dc:creator>Howard Hinnant</dc:creator>
		<pubDate>Sun, 26 Feb 2012 23:30:00 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1902</guid>
		<description>&lt;p&gt;I think you just hammered my first point above home.  Trying code:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
#include &lt;cstddef&gt;
#include &lt;new&gt;
#include &lt;utility&gt;

template &lt;class T&gt;
class MyVector
{
    T* begin_;
    T* end_;
    T* capacity_;

public:
    MyVector()
        : begin_(nullptr),
          end_(nullptr),
          capacity_(nullptr)
        {}

    ~MyVector()
    {
        clear();
        ::operator delete(begin_);
    }

    MyVector(std::size_t N, const T&amp; t)
        : MyVector()
    {
        if (N &gt; 0)
        {
            begin_ = end_ = static_cast&lt;T*&gt;(::operator new(N*sizeof(T)));
            capacity_ = begin_ + N;
            for (; N &gt; 0; --N, ++end_)
                ::new(end_) T(t);
        }
    }

    MyVector(const MyVector&amp; v)
        : MyVector()
    {
        std::size_t N = v.size();
        if (N &gt; 0)
        {
            begin_ = end_ = static_cast&lt;T*&gt;(::operator new(N*sizeof(T)));
            capacity_ = begin_ + N;
            for (std::size_t i = 0; i &lt; N; ++i, ++end_)
                ::new(end_) T(v[i]);
        }
    }

    MyVector(MyVector&amp;&amp; v)
        : begin_(v.begin_),
          end_(v.end_),
          capacity_(v.capacity_)
    {
        v.begin_ = nullptr;
        v.end_ = nullptr;
        v.capacity_ = nullptr;
    }

#ifndef USE_SWAP_ASSIGNMENT

    MyVector&amp; operator=(const MyVector&amp; v)
    {
        if (this != &amp;v)
        {
            std::size_t N = v.size();
            if (capacity() &lt; N)
            {
                clear();
                ::operator delete(begin_);
                begin_ = end_ = static_cast&lt;T*&gt;(::operator new(N*sizeof(T)));
                capacity_ = begin_ + N;
            }
            T* p = begin_;
            const T* q = v.begin_;
            for (; p &lt; end_ &amp;&amp; q &lt; v.end_; ++p, ++q)
                *p = *q;
            if (q &lt; v.end_)
            {
                for (; q &lt; v.end_; ++q, ++end_)
                    ::new(end_) T(*q);
            }
            else
            {
                while (end_ &gt; p)
                {
                    --end_;
                    end_-&gt;~T();
                }
            }
        }
        return *this;
    }

    MyVector&amp; operator=(MyVector&amp;&amp; v)
    {
        clear();
        swap(v);
        return *this;
    }

#else

    MyVector&amp; operator=(MyVector v)
    {
        swap(v);
        return *this;
    }

#endif

    void clear()
    {
        while (end_ &gt; begin_)
        {
            --end_;
            end_-&gt;~T();
        }
    }

    std::size_t size() const
        {return static_cast&lt;std::size_t&gt;(end_ - begin_);}
    std::size_t capacity() const
        {return static_cast&lt;std::size_t&gt;(capacity_ - begin_);}
    const T&amp; operator[](std::size_t i) const
        {return begin_[i];}
    T&amp; operator[](std::size_t i)
        {return begin_[i];}
    void swap(MyVector&amp; v)
    {
        std::swap(begin_, v.begin_);
        std::swap(end_, v.end_);
        std::swap(capacity_, v.capacity_);
    }
};

template &lt;class T&gt;
inline
void
swap(MyVector&lt;T&gt;&amp; x, MyVector&lt;T&gt;&amp; y)
{
    x.swap(y);
}

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;chrono&gt;

int main()
{
    MyVector&lt;std::string&gt; v1(1000, &quot;1234567890123456789012345678901234567890&quot;);
    MyVector&lt;std::string&gt; v2(1000, &quot;1234567890123456789012345678901234567890123456789&quot;);
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration&lt;double, std::micro&gt; US;
    auto t0 = Clock::now();
    v2 = v1;
    auto t1 = Clock::now();
    std::cout &lt;&lt; US(t1-t0).count() &lt;&lt; &quot; microseconds\n&quot;;
}

$ clang++ -stdlib=libc++ -std=c++11 -O3 -DUSE_SWAP_ASSIGNMENT test.cpp
$ a.out
174.516 microseconds
$ a.out
180.83 microseconds
$ a.out
175.848 microseconds

$ clang++ -stdlib=libc++ -std=c++11 -O3  test.cpp
$ a.out
26.339 microseconds
$ a.out
24.179 microseconds
$ a.out
24.103 microseconds
&lt;/pre&gt;&lt;/blockquote&gt;
</description>
		<content:encoded><![CDATA[<p>I think you just hammered my first point above home.  Trying code:</p>

<blockquote><pre>
#include &lt;cstddef&gt;
#include &lt;new&gt;
#include &lt;utility&gt;

template &lt;class T&gt;
class MyVector
{
    T* begin_;
    T* end_;
    T* capacity_;

public:
    MyVector()
        : begin_(nullptr),
          end_(nullptr),
          capacity_(nullptr)
        {}

    ~MyVector()
    {
        clear();
        ::operator delete(begin_);
    }

    MyVector(std::size_t N, const T&amp; t)
        : MyVector()
    {
        if (N &gt; 0)
        {
            begin_ = end_ = static_cast&lt;T*&gt;(::operator new(N*sizeof(T)));
            capacity_ = begin_ + N;
            for (; N &gt; 0; --N, ++end_)
                ::new(end_) T(t);
        }
    }

    MyVector(const MyVector&amp; v)
        : MyVector()
    {
        std::size_t N = v.size();
        if (N &gt; 0)
        {
            begin_ = end_ = static_cast&lt;T*&gt;(::operator new(N*sizeof(T)));
            capacity_ = begin_ + N;
            for (std::size_t i = 0; i &lt; N; ++i, ++end_)
                ::new(end_) T(v[i]);
        }
    }

    MyVector(MyVector&amp;&amp; v)
        : begin_(v.begin_),
          end_(v.end_),
          capacity_(v.capacity_)
    {
        v.begin_ = nullptr;
        v.end_ = nullptr;
        v.capacity_ = nullptr;
    }

#ifndef USE_SWAP_ASSIGNMENT

    MyVector&amp; operator=(const MyVector&amp; v)
    {
        if (this != &amp;v)
        {
            std::size_t N = v.size();
            if (capacity() &lt; N)
            {
                clear();
                ::operator delete(begin_);
                begin_ = end_ = static_cast&lt;T*&gt;(::operator new(N*sizeof(T)));
                capacity_ = begin_ + N;
            }
            T* p = begin_;
            const T* q = v.begin_;
            for (; p &lt; end_ &amp;&amp; q &lt; v.end_; ++p, ++q)
                *p = *q;
            if (q &lt; v.end_)
            {
                for (; q &lt; v.end_; ++q, ++end_)
                    ::new(end_) T(*q);
            }
            else
            {
                while (end_ &gt; p)
                {
                    --end_;
                    end_-&gt;~T();
                }
            }
        }
        return *this;
    }

    MyVector&amp; operator=(MyVector&amp;&amp; v)
    {
        clear();
        swap(v);
        return *this;
    }

#else

    MyVector&amp; operator=(MyVector v)
    {
        swap(v);
        return *this;
    }

#endif

    void clear()
    {
        while (end_ &gt; begin_)
        {
            --end_;
            end_-&gt;~T();
        }
    }

    std::size_t size() const
        {return static_cast&lt;std::size_t&gt;(end_ - begin_);}
    std::size_t capacity() const
        {return static_cast&lt;std::size_t&gt;(capacity_ - begin_);}
    const T&amp; operator[](std::size_t i) const
        {return begin_[i];}
    T&amp; operator[](std::size_t i)
        {return begin_[i];}
    void swap(MyVector&amp; v)
    {
        std::swap(begin_, v.begin_);
        std::swap(end_, v.end_);
        std::swap(capacity_, v.capacity_);
    }
};

template &lt;class T&gt;
inline
void
swap(MyVector&lt;T&gt;&amp; x, MyVector&lt;T&gt;&amp; y)
{
    x.swap(y);
}

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;chrono&gt;

int main()
{
    MyVector&lt;std::string&gt; v1(1000, "1234567890123456789012345678901234567890");
    MyVector&lt;std::string&gt; v2(1000, "1234567890123456789012345678901234567890123456789");
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration&lt;double, std::micro&gt; US;
    auto t0 = Clock::now();
    v2 = v1;
    auto t1 = Clock::now();
    std::cout &lt;&lt; US(t1-t0).count() &lt;&lt; " microseconds\n";
}

$ clang++ -stdlib=libc++ -std=c++11 -O3 -DUSE_SWAP_ASSIGNMENT test.cpp
$ a.out
174.516 microseconds
$ a.out
180.83 microseconds
$ a.out
175.848 microseconds

$ clang++ -stdlib=libc++ -std=c++11 -O3  test.cpp
$ a.out
26.339 microseconds
$ a.out
24.179 microseconds
$ a.out
24.103 microseconds
</pre></blockquote>
]]></content:encoded>
	</item>
	<item>
		<title>By: Matthias Vallentin</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1900</link>
		<dc:creator>Matthias Vallentin</dc:creator>
		<pubDate>Tue, 14 Feb 2012 00:32:36 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1900</guid>
		<description>&lt;p&gt;In the case of C++11, wouldn&#039;t it make sense to &lt;b&gt;always&lt;/b&gt; use the by-value version of the assignment operator &lt;b&gt;if&lt;/b&gt; a move constructor is provided in addition?&lt;/p&gt;

&lt;pre&gt;
T(T&amp;&amp; x)
{
     // Steal resources from x.
}

T&amp; operator=(T x)    // uses T(T&amp;&amp;) iff x is an r-value
{
    swap(*this, x);
    return *this;
}
&lt;/pre&gt;
</description>
		<content:encoded><![CDATA[<p>In the case of C++11, wouldn&#8217;t it make sense to <b>always</b> use the by-value version of the assignment operator <b>if</b> a move constructor is provided in addition?</p>

<pre>
T(T&amp;&amp; x)
{
     // Steal resources from x.
}

T&amp; operator=(T x)    // uses T(T&amp;&amp;) iff x is an r-value
{
    swap(*this, x);
    return *this;
}
</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: rhablersma</title>
		<link>http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/comment-page-1/#comment-1898</link>
		<dc:creator>rhablersma</dc:creator>
		<pubDate>Thu, 09 Feb 2012 14:00:53 +0000</pubDate>
		<guid isPermaLink="false">http://cpp-next.com/?p=188#comment-1898</guid>
		<description>&lt;p&gt;OK, I guess I should have asked a question to generate a reply. So here&#039;s a question: how can I make the above code avoid all unnecessary copies? Reading from the later installments of this blog series, I figure I need 4 overloads of operator+. Here&#039;s a first try:&lt;/p&gt;

&lt;pre&gt;template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;const std::vector&lt;T&gt;&amp; lhs, const std::vector&lt;T&gt;&amp; rhs&#041;
&#123;
        auto tmp = lhs;
        tmp.insert&#040;tmp.end&#040;&#041;, rhs.begin&#040;&#041;, rhs.end&#040;&#041;&#041;;
        return tmp;
&#125;
&#160;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;const std::vector&lt;T&gt;&amp; lhs, std::vector&lt;T&gt;&amp;&amp; rhs&#041;
&#123;
        rhs.insert&#040;rhs.begin&#040;&#041;, lhs.begin&#040;&#041;, lhs.end&#040;&#041;&#041;;
        return std::move&#040;rhs&#041;;
&#125;
&#160;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;std::vector&lt;T&gt;&amp;&amp; lhs, const std::vector&lt;T&gt;&amp; rhs&#041;
&#123;
        lhs.insert&#040;lhs.end&#040;&#041;, rhs.begin&#040;&#041;, rhs.end&#040;&#041;&#041;;
        return std::move&#040;lhs&#041;;
&#125;
&#160;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;std::vector&lt;T&gt;&amp;&amp; lhs, std::vector&lt;T&gt;&amp;&amp; rhs&#041;
&#123;
        lhs.insert&#040;lhs.end&#040;&#041;, rhs.begin&#040;&#041;, rhs.end&#040;&#041;&#041;;
        return std::move&#040;lhs&#041;;
&#125;&lt;/pre&gt;

&lt;p&gt;It&#039;s different from the Matrix example in this blog because operator+ is not commutative, and it&#039;s also different to the std::string example in the Nxxx standard proposal documents because std::vector does not have a built-in operator+=. So another question is: do I also need to have 4 overloads of operator+= to let std::vector have full append functionality? What signature would they have to have?&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>OK, I guess I should have asked a question to generate a reply. So here&#8217;s a question: how can I make the above code avoid all unnecessary copies? Reading from the later installments of this blog series, I figure I need 4 overloads of operator+. Here&#8217;s a first try:</p>

<pre>template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;const std::vector&lt;T&gt;&amp; lhs, const std::vector&lt;T&gt;&amp; rhs&#041;
&#123;
        auto tmp = lhs;
        tmp.insert&#040;tmp.end&#040;&#041;, rhs.begin&#040;&#041;, rhs.end&#040;&#041;&#041;;
        return tmp;
&#125;
&nbsp;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;const std::vector&lt;T&gt;&amp; lhs, std::vector&lt;T&gt;&amp;&amp; rhs&#041;
&#123;
        rhs.insert&#040;rhs.begin&#040;&#041;, lhs.begin&#040;&#041;, lhs.end&#040;&#041;&#041;;
        return std::move&#040;rhs&#041;;
&#125;
&nbsp;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;std::vector&lt;T&gt;&amp;&amp; lhs, const std::vector&lt;T&gt;&amp; rhs&#041;
&#123;
        lhs.insert&#040;lhs.end&#040;&#041;, rhs.begin&#040;&#041;, rhs.end&#040;&#041;&#041;;
        return std::move&#040;lhs&#041;;
&#125;
&nbsp;
template&lt;typename T&gt;
std::vector&lt;T&gt; operator+&#040;std::vector&lt;T&gt;&amp;&amp; lhs, std::vector&lt;T&gt;&amp;&amp; rhs&#041;
&#123;
        lhs.insert&#040;lhs.end&#040;&#041;, rhs.begin&#040;&#041;, rhs.end&#040;&#041;&#041;;
        return std::move&#040;lhs&#041;;
&#125;</pre>

<p>It&#8217;s different from the Matrix example in this blog because operator+ is not commutative, and it&#8217;s also different to the std::string example in the Nxxx standard proposal documents because std::vector does not have a built-in operator+=. So another question is: do I also need to have 4 overloads of operator+= to let std::vector have full append functionality? What signature would they have to have?</p>
]]></content:encoded>
	</item>
</channel>
</rss>

