将自定义函子与 std::generate_n() 算法一起使用的正确方法?

发布于 2024-07-07 15:01:47 字数 1276 浏览 6 评论 0原文

以下代码在 XPSP3 上的 VC++ 8 下可以正确编译,但运行它会导致运行时错误。

我的标头看起来像:

#include <stdexcept>
#include <iterator>
#include <list>


template<typename T>
class test_generator
{
    public:
    typedef T result_type;

    //constructor
    test_generator()
    {
        std::generate_n( std::back_inserter( tests ), 100, rand );
        value = tests.begin();
    }

    result_type operator()( void )
    {
        if( value == tests.end() )
        {
            throw std::logic_error( "" );
        }

            return *value++;
    }

    private:

    std::list<T> tests;
    typename std::list<T>::iterator value;

};

我的实现看起来像:

#include <functional>
#include <algorithm>
#include <iostream>
#include <deque>

#include "test.h"

int main()
{
    test_generator<double> test;
    std::deque<double> tests;

    std::generate_n( std::back_inserter( tests ), 10, test );

    return 0;
}

这编译得很好,它生成一个异常(不是标头中定义的logic_error异常)。

如果我更改实现以使用函数而不是函子,它就会起作用:

int main()
{
    std::deque<int> tests;
    std::generate_n( std::back_inserter( tests ), 10, rand );

    return 0;
}

这里使用函子有什么问题?

The following code compiles correctly under VC++ 8 on XPSP3, but running it causes a runtime error.

My header looks like:

#include <stdexcept>
#include <iterator>
#include <list>


template<typename T>
class test_generator
{
    public:
    typedef T result_type;

    //constructor
    test_generator()
    {
        std::generate_n( std::back_inserter( tests ), 100, rand );
        value = tests.begin();
    }

    result_type operator()( void )
    {
        if( value == tests.end() )
        {
            throw std::logic_error( "" );
        }

            return *value++;
    }

    private:

    std::list<T> tests;
    typename std::list<T>::iterator value;

};

My implementation looks like:

#include <functional>
#include <algorithm>
#include <iostream>
#include <deque>

#include "test.h"

int main()
{
    test_generator<double> test;
    std::deque<double> tests;

    std::generate_n( std::back_inserter( tests ), 10, test );

    return 0;
}

This compiles fine, it generates an exception (not the logic_error exception defined in the header).

If I change the implementation to use a function instead of a functor, it works:

int main()
{
    std::deque<int> tests;
    std::generate_n( std::back_inserter( tests ), 10, rand );

    return 0;
}

What's wrong with using a functor here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你在看孤独的风景 2024-07-14 15:01:47

test_generator 构造函数初始化 value 迭代器以引用 tests 列表中的第一个元素(它是 test_generator 的成员) >)。

当您调用 std::generate_n 时,会生成 test 的副本(因为该对象是按值传递的)。 在复制的对象中,value迭代器引用原始对象中的tests列表,而不是副本。

由于在 Visual Studio STL 实现中执行迭代器调试检查,这会触发断言,因为从一个容器获取的迭代器不应与来自另一容器的迭代器进行比较。

要解决此问题,您可以为 test_generator 类实现复制构造函数,或者推迟 value 的初始化,直到第一次使用 operator()被调用。

The test_generator constructor initialises the value iterator to reference the first element in the tests list (which is a member of test_generator).

When you call std::generate_n, a copy of the test is made (because the object is passed by value). In the copied object, the value iterator refers to the tests list in the original object, not the copy.

Because of the iterator debugging checks performed in the Visual Studio STL implementation, this triggers an assertion, because an iterator obtained from one container should not be compared against an iterator from another container.

To fix the problem, you could either implement a copy constructor for your test_generator class, or defer initialisation of value until the first time operator() is invoked.

月下伊人醉 2024-07-14 15:01:47

到目前为止,我还没有弄清楚是什么导致了异常,但您可能希望在 operator() 中使用 return *value++ 。 :-)

I haven't figured out what's causing the exception so far, but you may wish to have return *value++ in your operator(). :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文