2012-07-12 2 views
0

std :: transform을 사용하여 목록에있는 기존 값에 일부 값을 추가했습니다. 아래의 코드는 잘 작동하지만 변환을 실행할 때 복사 생성자 (프로그램의 출력 참조)에 대한 모든 호출을 피할 수 있는지 궁금합니다. 방금 코드를 해킹하고 for 루프가 Base의 + = 연산자를 명시 적으로 호출하면 복사 구성이 실행되지 않고 값이 더 효율적으로 변경됩니다.std :: transform이 생성자를 사용하는 이유는 무엇입니까?

복사를 구성하는 대신 Base의 + = 연산자를 변형 할 수 있습니까? 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; 
} 
+2

'std :: for_each'는 증분이 더 나은 술어, 여기서는 IMO입니다. – jrok

+0

팁 주셔서 감사합니다. 답변으로 작성하면 받아 들일 것입니다. – tmaric

+0

나는 완전히 질문에 대답하지 않는다고 생각하므로 코멘트를 남겨 두겠습니다 :'int counter = 4; std :: for_each (baseList.begin(), baseList.end(), [& counter] (int & i) {i + = counter ++;});'C++ 03에 머물고 싶다면 아마도 커스텀 펑터를 호출하고 이것을 'plus_assign'또는 이와 비슷한 방식으로 호출합니다. 나는 당신이 + =에'std :: plus'를 강제로 호출 할 수 있다고 생각하지 않는다. – jrok

답변

8

Base (const T& b) 그것이 const T& 받아 Base<T>의 생성자입니다, 복사 생성자가 아닙니다. 복사 생성자는 보통, 생성자는 당신이 당신의 덧셈 연산자에 일을 int에서 새로운 Base<int>을 만들 때마다 호출되는 것을 특징으로 서명 Base(const Base&)

있을 것입니다.

마지막으로 std :: transform()은 출력 반복기 할당 연산자를 사용하여 함수의 결과를 출력에 할당합니다. 복사본을 모두 피하려면을 사용하고 std::bind2nd(std::mem_fun_ref(&Base<int>::operator +=), 4))을 사용해야합니다. 이렇게하면 참조에 따라 작동하므로 사본을 만들지 않습니다.

+0

나는이 대답에서 아무것도 그에게 사본을 건너 뛸 수 있다고 생각하지 않습니까? –

+0

@MooingDuck, 그렇지 않습니다. 기존 객체를 수정하여 새로운 객체를 만드는'transform'을 사용하지 않기 때문에 가능합니다. –

+1

@JonathanWakely : 세 번째 단락은 내가 그 말을 할 때 존재하지 않았습니다. D _ 이제 _ 나는 +1 할 수 있습니다. –

관련 문제