У меня возникли проблемы с использованием объектов-функций в Visual Studio 2012.
Я создал простой std::vector
, добавил ints
0-9 и хотел создать сумму, используя объект функции. Мое определение класса (встроенное):
template <class T>
class Sum {
private:
T val;
public:
Sum (T i = 0) : val(i) {
}
void operator()(T x) {
val += x;
}
T result() const {
return val;
}
~Sum() {
std::cout << "Invoked destructor! val: " << val << " for this: " << this << std::endl;
}
};
Моя основная функция:
int main(int argc, char *argv[]){
Sum<int> s;
int contents[] = {1,2,3,4,5,6,7,8,9};
std::vector<int> vec = std::vector<int>(contents, contents + 9);
std::for_each(vec.begin(), vec.end(), s);
std::cout << "Sum of all numbers: " << s.result() << std::endl;
return 0;
}
Используя вывод из деструктора, я получу:
Invoked destructor! val: 45 for this: 003BFDA4
Invoked destructor! val: 45 for this: 003BFDE0
Sum of all numbers: 0
Invoked destructor! val: 0 for this: 003BFEFC
Это ошибка от VS? Проходя через него с помощью отладчика, элементы суммируются до 45
но сразу после этого деструктор вызывается. Что я делаю неправильно?
РЕДАКТИРОВАТЬ:
Это пример из Страуструпа The C++ Programming Language
Глава 18.4. Я просто подумал, что это не сработало, потому что я его точно скопировал.
Проблема в том, что std::for_each
принимает ваш аргумент функтора по значению. Это означает, что он работает с копией вашего оригинального объекта. Хорошей новостью является то, что он также возвращает ту копию, которая содержит измененное состояние. Это должно сделать трюк:
Sum<int> s1 = std::for_each(vec.begin(), vec.end(), s);
std::cout << "Sum of all numbers: " << s1.result() << std::endl;
В качестве альтернативы, вы могли бы позволить val
в вашем функторе быть ссылка к некоторой переменной:
template <class T>
class Sum {
private:
T& val;
public:
Sum (T& i) : val(i) {
}
// ...
Теперь это должно работать:
int i = 0;
Sum<int> s(i);
std::for_each(vec.begin(), vec.end(), s);
std::cout << "Sum of all numbers: " << s1.result() << std::endl;
Но вы должны позаботиться о том, чтобы срок службы i
достаточно расширен, чтобы не сделать Sum<T>::val
свисающая ссылка.
Других решений пока нет …