Бесконечная рекурсия в конструкторе копирования

У меня возникли проблемы в части моей программы, где я передаю объект, который действует как лямбда-функция, другой функции (мне нужно зафиксировать константу этого указателя, чтобы я не мог использовать настоящую лямбда). Это вызывает вызов конструктора копирования моей лямбды, который снова вызывает конструктор копирования, и в конечном итоге стек переполняется. Я понимаю, что происходит, но я не уверен, почему конструктор копирования вызывает сам себя или как это исправить. Я воспроизвел проблему ниже.

Компилятор: MSVC 2010

#include <functional>

void synchronizedExecution(std::function<void()> function) {
    function();
}

int main(int argc, char *argv[])
{

    int b = 0;

    class Function : public std::function<void()> {
    public:
        int& b;
        Function(int& b) :
            b(b) {}
        void operator()() {}
    } function(b);

    synchronizedExecution(function);

    return 0;
}

person HahaHortness    schedule 06.02.2014    source источник
comment
Объявление/определение класса внутри main() выглядит неправильно (по крайней мере, отсутствует точка с запятой после объявления!).   -  person πάντα ῥεῖ    schedule 06.02.2014
comment
Декларация выглядит просто отлично для меня. Точка с запятой стоит сразу после экземпляра.   -  person Fred Larson    schedule 06.02.2014
comment
Это нормально (без рекурсии) под g++... вы используете Visual Studio 2010 или 2012?   -  person IdeaHat    schedule 06.02.2014
comment
Объявление/определение класса в порядке - он просто использует альтернативный синтаксис, чтобы также объявить переменную класса и инициализировать ее с помощью конструктора, передавая b.   -  person Sion Sheevok    schedule 06.02.2014
comment
Наследовать от std::function — ужасная идея. Зачем ты это делаешь?   -  person Yakk - Adam Nevraumont    schedule 07.02.2014
comment
У меня была проблема с компиляцией, которая, казалось, исчезла, когда я унаследовал std::function. Это не соответствовало моему пониманию шаблонов, но мое понимание шаблонов не такое глубокое. С тех пор я удалил его и обнаружил, что он на самом деле ничего не делает.   -  person HahaHortness    schedule 07.02.2014
comment
@HahaHortness: У вас все еще есть рекурсия без наследования?   -  person Fred Larson    schedule 07.02.2014
comment
Нет, не знаю. Удаление суперкласса решило проблему.   -  person HahaHortness    schedule 15.02.2014


Ответы (2)


Я могу помочь вам с частью "как это исправить" - измените вашу функцию на

void synchronizedExecution(const std::function<void()>& function)
person PaF    schedule 06.02.2014
comment
Зависит, я могу видеть, где пользователь хотел бы, чтобы функция была фактически скопирована (поскольку synchronizedExecution - это функция, я предполагаю, что асинхронность также является вариантом) - person IdeaHat; 07.02.2014
comment
@MadScienceDreams: передача по значению будет нарезкой. Плохие новости. - person Fred Larson; 07.02.2014
comment
@FredLarson Я думал об этом, но он не загружается в g++, и я все еще пытаюсь понять, почему... - person IdeaHat; 07.02.2014
comment
@MadScienceDreams: Держу пари, он тоже не вызывает Function::operator()(). - person Fred Larson; 07.02.2014
comment
Мой код разрастался таким образом, что я думал, что даже если я перейду по ссылке, в какой-то момент мне придется скопировать функцию. Но теперь я не думаю, что это так, поэтому я думаю, что это сработает. - person HahaHortness; 07.02.2014
comment
@FredLarson Я думаю (могу ошибаться), что его код на самом деле интерпретируется как неявный конструктор типа функтора для std::function, а не как литеральный тип, поэтому он создает копию класса Function как член, а не его нарезается. У меня нет доказательств этого. - person IdeaHat; 07.02.2014
comment
@MadScienceDreams: На самом деле, я не думаю, что это сработает в любом случае, поскольку std::function::operator()() не является виртуальным. Он не предназначен для использования в качестве базового класса. - person Fred Larson; 07.02.2014
comment
@FredLarson добавил конструктор копирования вручную, std::function<void()> fun = function определенно вызывает Function::Function(const Function& fun), synchornizedExecution(function) дважды вызывает конструктор копирования (один раз для создания неявно приведенного std::function‹void()›, один раз для копирования в функцию). Так что никаких нарезок, по крайней мере, с настоящим C++11. - person IdeaHat; 07.02.2014
comment
@MadScienceDreams: теперь я понял, и ты прав. Здесь нет нарезки. - person Fred Larson; 07.02.2014

Во-первых, чтобы решить вашу проблему, вы, вероятно, можете передать объект по ссылке, а не по значению.

Во-вторых, ваш код очень подвержен ошибкам. Когда вы вводите новое имя, и оно совпадает с существующим, у вас возникает коллизия, которую компилятор решает, но вы не всегда получаете то, что ожидали. Например

   class Function
        int& b;
        Function(int& b) :
            b(b) {}

Я, честно говоря, не уверен, что b будет подставлено в (), член класса или параметр функции. AFAIR, член класса имеет приоритет, и это не то, что вы хотели. Я подозреваю, что ваша реальная проблема имеет ту же причину.

person Michael Simbirsky    schedule 06.02.2014