【问题标题】:Functor's instance variable is not kept between consecutive calls to generate_n在对 generate_n 的连续调用之间不保留 Functor 的实例变量
【发布时间】:2012-05-13 09:44:36
【问题描述】:

我使用以下结构作为 STL 的 generate_n 算法的输入:

struct GenerateNumber {     
    GenerateNumber () : i(0) {}
    int operator () (void) {        
        return  i++;
    }
private:
    int i;
};

使用此函子的代码示例如下:

std::vector <int> v1 (3);
std::vector <int> v2 (3);
GenerateNumber generateNumber;
std::generate_n (v1.begin (), 3, generateNumber);
std::generate_n (v2.begin (), 3, generateNumber);

但是,结果是v1v2 都包含{0,1,2},而不是v2 包含{3,4,5}。我已经用断点验证了 GenerateNumber 的构造函数只被调用一次(我知道构造函数被多次调用是没有意义的,但我还是检查了它)。

我知道我可以通过将i 设为静态来解决此问题,但我不明白这种行为。为什么连续调用之间不保留i 的值?

【问题讨论】:

    标签: c++ stl functor


    【解决方案1】:

    生成器对象在传递给generate_n 时被复制。尝试使用std::ref,即

    std::generate_n(v1.begin(), 3, std::ref(generateNumber));
    std::generate_n(v2.begin(), 3, std::ref(generateNumber));
    

    编辑:请注意,std::ref 仅在 C++11 中可用。它在 TR1 中以 std::tr1::ref 的形式引入,并且在 boost 中也以 boost::ref 的形式提供。

    【讨论】:

    • 你应该提到std::ref是C++11(虽然TR1中也提到过)。
    • 我可能不得不坚持使用static 解决方案,因为我需要我的代码在 VS2010(实现 c++11)和 GCC 4.4(不实现)中编译。但是,为了完整起见,当我使用您的建议时,会出现以下编译错误:error C2679: binary '=' : no operator found which takes a right-hand operand of type 'void' (or there is no acceptable conversion) C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm 1581
    • @LucDanton:感谢您的来信。有时我忘记了,在 C++11 之前有一段时间。
    • @ItamarKatz 我添加了一个解决方案,该解决方案可以为您工作,而无需求助于静态。
    • 似乎编译器找不到std::tr1::ref - 它确实找到了std::tr1::reference_wrapper,但我仍然遇到相同的编译错误。我会继续努力的。
    【解决方案2】:

    std::generate_n 按值获取函子,即复制它。可能是您没有检查 复制构造函数 是否被调用。

    在没有std::ref 的情况下,并且如果您的问题如您的示例中那样本地化,您可以修改您的仿函数以引用在对std::generate_n 的调用范围内设置的计数器:

    struct GenerateNumber {     
        GenerateNumber (int& i) : struct GenerateNumber {     
        GenerateNumber () : i(0) {}
        int operator () (void) {        
            return  i++;
        }
    private:
        int& i;
    };
    
    int main() {
      int counter = 0;
      std::vector <int> v1 (3);
      std::vector <int> v2 (3);
      GenerateNumber generateNumber(counter);
      std::generate_n (v1.begin (), 3, generateNumber);
      std::generate_n (v2.begin (), 3, generateNumber);
    
    }
    

    【讨论】:

    • 谢谢,这是一个优雅的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 2014-03-06
    • 2012-02-12
    相关资源
    最近更新 更多