Как изменить элементы контейнера?
От: gruid  
Дата: 11.06.02 00:42
Оценка:
не подскажите.


std::vector<int> a;
...
for_each(a.begin(), a.end(), ... ) ;


вызывает что-то с константным объектом в параметре, т.е. не изменяет элементы контейнера,
А как нада писать чтобы например увеличить все эл-ты контейнера в 2 раза
Re: Как изменить элементы контейнера?
От: Андрей Россия  
Дата: 11.06.02 02:21
Оценка:
Здравствуйте gruid, Вы писали:

skip

G>вызывает что-то с константным объектом в параметре, т.е. не изменяет элементы контейнера,

G>А как нада писать чтобы например увеличить все эл-ты контейнера в 2 раза

Используй std::transform
Re: Как изменить элементы контейнера?
От: Vyacheslav Koltovich  
Дата: 11.06.02 02:24
Оценка:
Здравствуйте gruid, Вы писали:


G>не подскажите.



G>
G>std::vector<int> a;
G>...
G>for_each(a.begin(), a.end(), ... ) ;
G>


G>вызывает что-то с константным объектом в параметре, т.е. не изменяет элементы контейнера,

G>А как нада писать чтобы например увеличить все эл-ты контейнера в 2 раза

Можно просто перебрать элементы:
for (std::vector<int>::iterator ii=vec.begin(); ii!=vec.end();ii++)
{
    (*ii) *= 2;
}


Либо есть еше вариант, в контейнере указатели хранить,но это уже попахивает каким-то извратом
Re: Как изменить элементы контейнера?
От: _DEBUG Беларусь  
Дата: 11.06.02 03:16
Оценка: 6 (2)
Здравствуйте gruid, Вы писали:


G>не подскажите.



G>
G>std::vector<int> a;
G>...
G>for_each(a.begin(), a.end(), ... ) ;
G>


G>вызывает что-то с константным объектом в параметре, т.е. не изменяет элементы контейнера,

G>А как нада писать чтобы например увеличить все эл-ты контейнера в 2 раза


// alg_for_each.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <iostream>

// The function object multiplies an element by a Factor
template <class Type>
class MultValue
{
private:
   Type Factor;   // The value to multiply by
public:
   // Constructor initializes the value to multiply by
   MultValue ( const Type& _Val ) : Factor ( _Val ) {
   }

   // The function call for the element to be multiplied
   void operator ( ) ( Type& elem ) const
   {
      elem *= Factor;
   }
};

// The function object to determine the average
class Average
{
private:
   long num;      // The number of elements
   long sum;      // The sum of the elements
public:
   // Constructor initializes the value to multiply by
   Average ( ) : num ( 0 ) , sum ( 0 )
   {
   }

   // The function call to process the next elment
   void operator ( ) ( int elem )    {
      num++;      // Increment the element count
      sum += elem;   // Add the value to the partial sum
   }

   // return Average
   operator double ( )
   {
      return  static_cast <double> (sum) /
      static_cast <double> (num);
   }
};

int main( )
{
   using namespace std;
   vector <int> v1;
   vector <int>::iterator Iter1;

   // Constructing vector v1
   int i;
   for ( i = -4 ; i <= 2 ; i++ )
   {
      v1.push_back(  i );
   }

   cout << "Original vector  v1 = ( " ;
   for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
      cout << *Iter1 << " ";
   cout << ")." << endl;

   // Using for_each to multiply each element by a Factor
   for_each ( v1.begin ( ) , v1.end ( ) , MultValue<int> ( -2 ) );

   cout << "Multiplying the elements of the vector v1\n "
        <<  "by the factor -2 gives:\n v1mod1 = ( " ;
   for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
      cout << *Iter1 << " ";
   cout << ")." << endl;

   // The function object is templatized and so can be
   // used again on the elements with a different Factor
   for_each (v1.begin ( ) , v1.end ( ) , MultValue<int> (5 ) );

   cout << "Multiplying the elements of the vector v1mod\n "
        <<  "by the factor 5 gives:\n v1mod2 = ( " ;
   for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
      cout << *Iter1 << " ";
   cout << ")." << endl;

   // The local state of a function object can accumulate
   // information about a sequence of actions that the
   // return value can make available, here the Average
   double avemod2 = for_each ( v1.begin ( ) , v1.end ( ) ,
      Average ( ) );
   cout << "The average of the elements of v1 is:\n Average ( v1mod2 ) = "
        << avemod2 << "." << endl;
}


Output
Original vector v1 = ( -4 -3 -2 -1 0 1 2 ).
Multiplying the elements of the vector v1
by the factor -2 gives:
v1mod1 = ( 8 6 4 2 0 -2 -4 ).
Multiplying the elements of the vector v1mod
by the factor 5 gives:
v1mod2 = ( 40 30 20 10 0 -10 -20 ).
The average of the elements of v1 is:
Average ( v1mod2 ) = 10.
\n Give me MSDN and I'll show you the world
Re[2]: Как изменить элементы контейнера?
От: Pavel XP  
Дата: 11.06.02 05:20
Оценка:
Здравствуйте _DEBUG, Вы писали:

D>Здравствуйте gruid, Вы писали:



G>>не подскажите.



G>>
G>>std::vector<int> a;
G>>...
G>>for_each(a.begin(), a.end(), ... ) ;
G>>


G>>вызывает что-то с константным объектом в параметре, т.е. не изменяет элементы контейнера,

G>>А как нада писать чтобы например увеличить все эл-ты контейнера в 2 раза


D>
D>// alg_for_each.cpp
D>// compile with: /EHsc
D>#include <vector>
D>#include <algorithm>
D>#include <iostream>

D>// The function object multiplies an element by a Factor
D>template <class Type>
D>class MultValue
D>{
D>private:
D>   Type Factor;   // The value to multiply by
D>public:
D>   // Constructor initializes the value to multiply by
D>   MultValue ( const Type& _Val ) : Factor ( _Val ) {
D>   }

D>   // The function call for the element to be multiplied
D>   void operator ( ) ( Type& elem ) const
D>   {
D>      elem *= Factor;
D>   }
D>};
   skip
D>int main( )
D>{
D>   using namespace std;
D>   vector <int> v1;
D>   vector <int>::iterator Iter1;

D>   // Constructing vector v1
D>   int i;
D>   for ( i = -4 ; i <= 2 ; i++ )
D>   {
D>      v1.push_back(  i );
D>   }

D>   cout << "Original vector  v1 = ( " ;
D>   for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )
D>      cout << *Iter1 << " ";
D>   cout << ")." << endl;

D>   // Using for_each to multiply each element by a Factor
D>   for_each ( v1.begin ( ) , v1.end ( ) , MultValue<int> ( -2 ) );

D>   
D>}

D>


Вопрос, а почему это работает?
Ведь в
void MultValue::operator ( ) ( Type& elem ) const
не const Type& elem в параметре
Re[2]: Как изменить элементы контейнера?
От: Bell Россия  
Дата: 11.06.02 05:29
Оценка:
Здравствуйте _DEBUG, Вы писали:

D>Здравствуйте gruid, Вы писали:



D>// The function object to determine the average
D>class Average
D>{
D>private:
D>   long num;      // The number of elements
D>   long sum;      // The sum of the elements
D>public:
D>   // Constructor initializes the value to multiply by
D>   Average ( ) : num ( 0 ) , sum ( 0 )
D>   {
D>   }

D>   // The function call to process the next elment
D>   void operator ( ) ( int elem )    {
D>      num++;      // Increment the element count
D>      sum += elem;   // Add the value to the partial sum
D>   }

D>   // return Average
D>   operator double ( )
D>   {
D>      return  static_cast <double> (sum) /
D>      static_cast <double> (num);
D>   }
D>};


Ну не стал бы я так делать. Наличие неявных преобразований, скажем так, редко упрощает понимание кода
К тому же вместо
D>   // The local state of a function object can accumulate
D>   // information about a sequence of actions that the
D>   // return value can make available, here the Average
D>   double avemod2 = for_each ( v1.begin ( ) , v1.end ( ) ,
D>      Average ( ) );


можно написать
double avemod2 = for_each(v1.begin(), v1.end(), Average()).getResult();

предварительно определив в классе Average метод getResult вместо оператора преобразования.

ИМХО несколько нагляднее...
Любите книгу — источник знаний (с) М.Горький
Re[3]: Как изменить элементы контейнера?
От: Bell Россия  
Дата: 11.06.02 05:33
Оценка:
Здравствуйте Pavel XP, Вы писали:


PX> Вопрос, а почему это работает?

PX>Ведь в
PX>void MultValue::operator ( ) ( Type& elem ) const
PX>не const Type& elem в параметре

Ну так потому и работает
Вот если бы было
void MultValue::operator ( ) ( const Type& elem ) const

тогда бы точно не работало. Как прикажешь модифицировать объект через константную ссылку?!
Любите книгу — источник знаний (с) М.Горький
Re[4]: Как изменить элементы контейнера?
От: Pavel XP  
Дата: 11.06.02 05:58
Оценка:
Здравствуйте Bell, Вы писали:

B>Здравствуйте Pavel XP, Вы писали:



PX>> Вопрос, а почему это работает?

PX>>Ведь в
PX>>void MultValue::operator ( ) ( Type& elem ) const
PX>>не const Type& elem в параметре

B>Ну так потому и работает

B>Вот если бы было
B>
B>void MultValue::operator ( ) ( const Type& elem ) const
B>

B>тогда бы точно не работало. Как прикажешь модифицировать объект через константную ссылку?!


Так и такое правильно работает?


void fff(int& x)
{
   x*=2;
}



   std::vector<int> a(10, 5);

   std::for_each(a.begin(), a.end(), fff);


А как то же что этот for_each для немодифицирующихся последовательностей.
Re[5]: Как изменить элементы контейнера?
От: Bell Россия  
Дата: 11.06.02 06:28
Оценка:
Здравствуйте Pavel XP, Вы писали:


PX>Так и такое правильно работает?



PX>
PX>void fff(int& x)
PX>{
PX>   x*=2;
PX>}



PX>   std::vector<int> a(10, 5);

PX>   std::for_each(a.begin(), a.end(), fff);

PX>


Ну да, после всего этого в векторе будут десятки

PX>А как то же что этот for_each для немодифицирующихся последовательностей.

Ну во-первых в нужной функции в качестве параметра можно исплльзовать константную ссылку.
Во-вторых можно написать так:
std::vector<int>::const_iterator itBegin = a.begin();
std::vector<int>::const_iterator itEnd = a.end();
std::for_each(itBegin, itEnd, fff);

Тогда в случае, если fff может модифицировать свой аргумент (т.е. тип аргумента — не константная ссылка), при компиляции компилятор ругнется, что позволит сделать определенные выводы...
Любите книгу — источник знаний (с) М.Горький
Re: Как изменить элементы контейнера?
От: Юнусов Булат Россия  
Дата: 11.06.02 12:16
Оценка:
Думается, что для такой данной задачи удобнее std::valarray

    std::valarray<int> Values(2, 5); // к примеру инициализируем пятью двойками
    Values *= 2;
Re: Как изменить элементы контейнера?
От: Павел Кузнецов  
Дата: 11.06.02 13:36
Оценка: 3 (1)
Здравствуйте gruid, Вы писали:

G>std::vector<int> a;
G>...
G>for_each(a.begin(), a.end(), ... ) ;


G>вызывает что-то с константным объектом в параметре, т.е. не изменяет элементы контейнера


Насколько я понимаю, это одно из достаточно распространенных заблуждений о std::for_each, вызванное тем, что (1) в стандарте std::for_each отнесен к категории так называемых Non-modifying sequence operations, и, кроме того, (2) тем, что std::for_each требует в качестве итератора InputIterator.

Первое означает, что сам алгоритм не изменяет значения элементов последовательности, для которой он вызван, т.е., попросту говоря, не содержит фрагмента: *it = ... . Сам же функциональный объект, переданный std::for_each в качестве аргумента, вполне может, в качестве побочного эффекта, изменять значения элементов последовательности. Второе требование заключается в том, что итератор, переданный в std::for_each должен быть, как минимум, InputIterator. Ничто не запрещает передавать в std::for_each mutable итератор.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Как изменить элементы контейнера?
От: m.a.g. Мальта http://dottedmag.net/
Дата: 12.06.02 06:12
Оценка:
Здравствуйте Vyacheslav Koltovich, Вы писали:

VK>Можно просто перебрать элементы:

VK>
VK>for (std::vector<int>::iterator ii=vec.begin(); ii!=vec.end();ii++)
VK>{
VK>    (*ii) *= 2;
VK>}
VK>


VK>Либо есть еше вариант, в контейнере указатели хранить,но это уже попахивает каким-то извратом


Вышеприведенный код тоже попахивает извратом. Есть же готовые алгоритмы для этого:

transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>, 2));
Re[2]: Как изменить элементы контейнера?
От: WeCom Беларусь  
Дата: 12.06.02 09:33
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

ПК>Сам же функциональный объект, переданный std::for_each в качестве аргумента, вполне может, в качестве побочного эффекта, изменять значения элементов последовательности. ... Ничто не запрещает передавать в std::for_each mutable итератор.


Вот что мне после этого интересно. Если у меня например есть map или set и в for_each я изменяю *it, то каким образом сможет этот самый for_each пройти весь контейнер по-порядку от начала до конца? Разве изменение элемента в этих типах контейнеров не модифицирует сам контейнер (порядок элементов)?
Re[3]: Как изменить элементы контейнера?
От: Павел Кузнецов  
Дата: 12.06.02 10:04
Оценка:
Здравствуйте WeCom, Вы писали:

ПК>>Сам же функциональный объект, переданный std::for_each в качестве аргумента, вполне может, в качестве побочного эффекта, изменять значения элементов последовательности. ... Ничто не запрещает передавать в std::for_each mutable итератор.


WC>Вот что мне после этого интересно. Если у меня например есть map или set и в for_each я изменяю *it, то каким образом сможет этот самый for_each пройти весь контейнер по-порядку от начала до конца? Разве изменение элемента в этих типах контейнеров не модифицирует сам контейнер (порядок элементов)?


Итераторы std::map не позволяют изменять ключи, т.к. при разыменовании дают std::pair<const Key, const Type>&. Итераторы std::set не позволяют изменять элементы std::set, т.е. не являются mutable iterators. Даже в тех реализациях STL, которые не приняли к сведению соответствующее сообщение о дефекте в стандарте, и в которых итераторы множества позволяют изменять элементы контейнера, изменение элементов, приводящее к изменению порядка, нарушает целостность контейнера. Так что, нет, ты не сможешь изменить порядок элементов в контейнерах std::set и std::map, изменив значение элемента в функциональном объекте, переданном в std::for_each.

Однако, конечно, можно помешать работе std::for_each, добавив в std::vector какое-то количество элементов и нарушив целостность итераторов в процессе выполнения алгоритма. Что ж, здравый смысл никто не отменял...
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Как изменить элементы контейнера?
От: Павел Кузнецов  
Дата: 12.06.02 10:35
Оценка:
ПК>Итераторы std::map не позволяют изменять ключи, т.к. при разыменовании дают std::pair<const Key, const Type>&.

Sorry, здесь должно было быть: std::pair<const Key, Type>&
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Как изменить элементы контейнера?
От: Vyacheslav Koltovich  
Дата: 13.06.02 00:56
Оценка:
Здравствуйте m.a.g., Вы писали:

...>Здравствуйте Vyacheslav Koltovich, Вы писали:


VK>>Можно просто перебрать элементы:

VK>>
VK>>for (std::vector<int>::iterator ii=vec.begin(); ii!=vec.end();ii++)
VK>>{
VK>>    (*ii) *= 2;
VK>>}
VK>>


VK>>Либо есть еше вариант, в контейнере указатели хранить,но это уже попахивает каким-то извратом


...>Вышеприведенный код тоже попахивает извратом. Есть же готовые алгоритмы для этого:


...>
...>transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>, 2));
...>


Да, но в случае множества простых,не связанных и выполняемых однократно изменений элементов контейнера получаем либо огромное количество простых функций либо функцию с большим свитчем, что уже не очень хорошо.
Re[4]: Как изменить элементы контейнера?
От: m.a.g. Мальта http://dottedmag.net/
Дата: 13.06.02 05:00
Оценка:
Здравствуйте Vyacheslav Koltovich, Вы писали:

...>>Вышеприведенный код тоже попахивает извратом. Есть же готовые алгоритмы для этого:


...>>
...>>transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>, 2));
...>>


VK>Да, но в случае множества простых,не связанных и выполняемых однократно изменений элементов контейнера получаем либо огромное количество простых функций либо функцию с большим свитчем, что уже не очень хорошо.


Возникает вопрос: а зачем нужны эти "простые, не связанные и выполняемые однократно изменения элементов контейнера"? Первое впечатление — ошибка проектирования.
Re[4]: Как изменить элементы контейнера?
От: m.a.g. Мальта http://dottedmag.net/
Дата: 13.06.02 05:02
Оценка:
Здравствуйте Vyacheslav Koltovich, Вы писали:

...>>Вышеприведенный код тоже попахивает извратом. Есть же готовые алгоритмы для этого:


...>>
...>>transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>, 2));
...>>


VK>Да, но в случае множества простых,не связанных и выполняемых однократно изменений элементов контейнера получаем либо огромное количество простых функций либо функцию с большим свитчем, что уже не очень хорошо.


Кстати, чем это плохо? Ведь "огромное количество простых функций" очень хорошо заинлайнится. А если использовать lambda library, то их вообще выписывать отдельно не надо будет.
Re[3]: Как изменить элементы контейнера?
От: Андрей Тарасевич Беларусь  
Дата: 13.06.02 05:46
Оценка:
Здравствуйте Pavel XP, Вы писали:

PX> Вопрос, а почему это работает?

PX>Ведь в
PX>void MultValue::operator ( ) ( Type& elem ) const
PX>не const Type& elem в параметре

А кто сказал, что там должно быть const в параметре?
Best regards,
Андрей Тарасевич
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.