0

std::transform を使用して、リスト内の既存の値にいくつかの値を追加しました。以下のコードは問題なく動作します。transform の実行時に、コピー コンストラクター (プログラムの出力を参照) へのすべての呼び出しを回避できるかどうか疑問に思っています。コードをハックして、for ループで Base の += 演算子を明示的に呼び出すようにすると、コピーの作成は実行されず、値がその場で変更され、より効率的になります。

コピー構築の代わりに変換で Base の operator+= を呼び出すことはできますか? に集中すべきincrement<Type>ですか?

プログラム:

#include <iostream>
#include<list>
#include <algorithm>
#include <iterator>

template<class T>
class Base;

template<class T>
std::ostream& operator << (std::ostream& os, const Base<T>& b);

template<class T>
class Base
{
    private: 
        T b_;
    public: 
        typedef T value_type;

        Base()
            :
                b_()
        { std::cout << "Base::def ctor" << std::endl; }

        Base (const T& b)
            : 
                b_(b)
        { std::cout << "Base::implicit conversion ctor: " << b_ << std::endl; }

        const T& value()
        {
            return b_;
        }

        const Base operator+(const Base& b) const
        {
            std::cout << "Base operator+ " << std::endl;
            return Base(b_ + b.b_);
        }

        const Base&  operator+=(const T& t) 
        {
            b_ += t;
            return *this;
        }

        friend std::ostream& operator<< <T> (std::ostream& os, const Base<T>& b);
};

template<class T>
std::ostream& operator<< (std::ostream& os, const Base<T>& b)
{
    os << b.b_; 
    return os;
}

template<class Type> 
class increment
{
    typedef typename Type::value_type T; 

    T initial_; 

    public: 

        increment()
            :
                initial_()
        {};

        increment(const T& t)
            :
                initial_(t)
        {}

        T operator()()
        {
            return initial_++;
        }
};

template<class Container>
void write(const Container& c)
{
    std::cout << "WRITE: " << std::endl;
    copy(c.begin(), c.end(), 
         std::ostream_iterator<typename Container::value_type > (std::cout, " "));
    std::cout << std::endl;
    std::cout << "END WRITE" << std::endl;
}

using namespace std;

int main(int argc, const char *argv[])
{
    typedef list<Base<int> > bList; 

    bList baseList(10); 

    cout << "GENERATE" << endl;
    generate_n (baseList.begin(), 10, increment<Base<int> >(10));
    cout << "END GENERATE" << endl;

    write(baseList); 

    // Let's add some integers to Base<int>

    cout << "TRANSFORM: " << endl;

    std::transform(baseList.begin(), baseList.end(), 
                   baseList.begin(), 
                   bind2nd(std::plus<Base<int> >(), 4)); 
    cout << "END TRANSFORM " << endl;

    write(baseList);

    // Hacking the code: 
    cout << "CODE HACKING: " << endl;
    int counter = 4;
    for (bList::iterator it = baseList.begin(); 
         it != baseList.end(); 
         ++it)
    {
        *it += counter; // Force the call of the operator+=
        ++counter;
    }
    write (baseList);
    cout << "END CODE HACKING" << endl;

    return 0;
}
4

1 に答える 1

8

Base (const T& b)はコピーコンストラクタではなく、Base<T>を受け入れるためのコンストラクタですconst T&。コピーコンストラクターには通常、署名がありますBase(const Base& )

とは言うものの、コンストラクターは、加算演算子で実行しているBase<int>から新しいものを作成するたびに呼び出されます。int

最後に、std :: transform()は、出力イテレータ代入演算子を使用して、関数の結果を出力に代入します。コピーを完全に避けたい場合はstd::for_each、を一緒に使用する必要がありますstd::bind2nd( std::mem_fun_ref(&Base<int>::operator +=), 4 ))。これにより、参照に対してsoleyが機能するため、コピーを作成する必要がなくなります。

于 2012-07-12T14:31:04.427 に答える