开发者

Boost Fusion container of shared pointers (shared_ptr) causing Segmentation Fault (sigsegv) or garbage results

Edit: This turned out to be an issue with temporaries. Basically, I was ignorantly using C++ as if it worked like Java or C#, which it does not. Hopefully, this will be a good cautionary tale.

Edit: This issue only seems to happen with the combination of joint_view and shared_ptr. Raw pointers seem to work fine in the same scenario, as do shared pointers in a plain fusion container constructed w/ all its items at once, without adding anything more to it. Details below:

I'm using mingw gcc 4.5.1 Running into a peculiar issue when using boost fusion container(s) and getting contents back out. I have a custom class that gets wrapped in a std::shared_ptr, then that's handed to a fusion make_list() (or make_vector(), doesn't seem to matter). All is well if I can get all of my objects into the container at one time. The problem seems to come up when I add another shared pointer to the container, which yields a joint_view. I iterate using a fusion::for_each() and pass in a function object to print out the value. If I'm iterating a plain fusion container of shared pointers instead of a joint_view, or a joint_view with no shared pointers in it, it works fine, but otherwise, segmentation fault or garbage values.

Below is a test program I made to try and isolate my problem. Any ideas on what the issue may be? It's entirely possible I'm just missing something that I should/shouldn't be doing :(

#include <iostream>
#include <memory>

//BOOST SMART POINTERS
//I only use boost's shared_ptr for ONE test, results are the same.
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

//BOOST FUSION
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/container/generation/make_list.hpp>
#include <boost/fusion/include/make_list.hpp>
#include <boost/fusion/container/generation/make_vector.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/algorithm/transformation/push_back.hpp>
#include <boost/fusion/include/push_back.hpp>

using namespace std;
using namespace boost::fusion;

struct TestStructInt {
    int test_int;

    TestStructInt(int init_num) : test_int(init_num) {};
};

struct TestStructString {
    string test_string;

    TestStructString(string init_str) : test_string(init_str) {};
};

struct do_junk{
    void operator()(string t) const {
        cout << t << endl;
    }

    void operator()(string* t) const {
        cout << *t << endl;
    }

    void operator()(std::shared_ptr<int> t) const {
        cout << *t << endl;
    }

    void operator()(std::shared_ptr<string> t) const {
        cout << *t << endl;
    }

    void operator() (boost::shared_ptr<string> t) const {
        cout << *t << endl;
    }

    void operator() (TestStructInt t) const {
        cout << t.test_int << endl;
    }

    void operator() (std::shared_ptr<TestStructInt> t) const {
        cout << t->test_int << endl;
    }

    void operator() (TestStructString t) const {
        cout << t.test_string << endl;
    }

    void operator() (std::shared_ptr<TestStructString> t) const {
        cout << t->test_string << endl;
    }

    void operator() (std::shared_ptr<TestStructString*> t) const {
        cout << (*t)->test_string << endl;
    }
};

int main()
{
    string foo1 = "foo1";
    string foo2 = "foo2";
    string foo3 = "foo3";
    int bar1 = 1;
    int bar2 = 2;
    int bar3 = 3;
    string* foo1_ptr = &foo1;
    string* foo2_ptr = &foo2;
    string* foo3_ptr = &foo3;
    auto foo1_obj = make_shared<TestStructString>(TestStructString("foo1"));
    auto foo2_obj = make_shared<TestStructString>(TestStructString("foo2"));
    auto foo3_obj = make_shared<TestStructString>(TestStructString("foo3"));

    //works fine
    auto list_test1 = make_list(foo1, foo2);

    //works fine
    auto list_test2 = make_list(foo1_ptr, foo2_ptr);

    //seems to work, but is undefined behavior
    auto list_test3
        = make_list(
            std::make_shared<int>(bar1), std::make_shared<int>(bar2)
        )
    ;

    //seems to work, but is undefined behavior
    auto list_test4
        = make_list(
            std::make_shared<string>(foo1), std::make_shared<string>(foo2)
        )
    ;

    //seems to work, but is undefined behavior
    auto list_test5
        = make_list(
            std::make_shared<TestStructInt>(TestStructInt(1))
            , std::make_shared<TestStructInt>(TestStructInt(2))
        )
    ;

    //seems to work, but is undefined behavior
    auto list_test6
        = make_list(
            std::make_shared<TestStructString>(TestStructString("foo1"))
            , std::make_shared<TestStructString>(TestStructString("foo2"))
        )
    ;

    //seems to work, but is undefined behavior
    auto list_test7
        = make_list(TestStructString("foo1"), TestStructString("foo2"))
    ;

    //seems to work, but is undefined behavior
    auto joint_view_test1 = push_back(make_list(foo1, foo2), foo3);

    //seems to work, but is undefined behavior
    auto joint_view_test2 = push_back(make_list(foo1_ptr, foo2_ptr), foo3_ptr);

    //seems to work, but is undefined behavior
    auto joint_view_test3
        = push_back(
            make_list(
                TestStructString(foo1), TestStructString(foo2)
            )
            , TestStructString(foo3)
        )
    ;

    //integer values I pass in are coming out different
    auto joint_view_test4
        = push_back(
            make_list(
                std::make_shared<int>(bar1), std::make_shared<int>(bar2)
            )
            , make_shared<int>(bar3)
        )
    ;

    //pass in foo1, foo2, and foo3, but only get foo3's value back out for each
    auto joint_view_test5
        = push_back(
            make_list(
                std::make_shared<string>(foo1), std::make_shared<string>(foo2)
            )
            , make_shared<string>(foo3)
        )
    ;

    //causes seg fault when running do_junk()
    auto joint_view_test6
        = push_back(
            make_vector(
                std::make_shared<string>(foo1), std::make_shared<string>(foo2)
            )
            , std::make_shared<string>(foo3)
        )
    ;

    //causes seg fault when running do_junk()
    auto joint_view_test7
        = push_back(
            make_list(
                boost::make_shared<string>(foo1)
                , boost::make_shared<string>(foo2)
            )
            , boost::make_shared<string>(foo3)
        )
    ;

    //integer values I pass in are coming out different
    auto joint_view_test8
        = push_back(
            make_list(
                std::make_shared<TestStructInt>(TestStructInt(1))
                , std::make_shared<TestStructInt>(TestStructInt(2))
            )
            , std::make_shared<TestStructInt>(TestStructInt(3))
        )
    ;

    //causes seg fault when running do_junk()
    auto joint_view_test9
        = push_back(
            make_list(
                std::make_shared<TestStructString>(TestStructString("foo1"))
                , std::make_shared<TestStructString>(TestStructString("foo2"))
            )
            , std::make_shared<TestStructString>(TestStructString("foo3"))
        )
    ;

    //causes seg fault when running do_junk()
    auto joint_view_test10
        = push_back(
            make_list(
                std::make_shared<TestStructString*>(new TestStructString("foo1"))
                , std::make_shared<TestStructString*>(new TestStructString("foo2"))
            )
            , std::make_shared<TestStructString*>(new TestStructString("foo3"))
        )
    ;

    //seems to work, but is undefined behavior
    auto joint_view_test11
        = push_back(
            make_list(
                foo1_obj
                , foo2_obj
            )
            , foo3_obj
        )
    ;

    cout << "@@ list1" << endl;
    boost::fusion::for_each(list_test1, do_junk());
    cout << "@@ list2" << endl;
    boost::fusion::for_each(list_test2, do_junk());
    cout << "@@ list3" << endl;
    boost::fusion::for_each(list_test3, do_junk());
    cout << "@@ list4" << endl;
    boost::fusion::for_each(list_test4, do_junk());
    cout << "@@ list5" << endl;
    boost::fusion::for_each(list_test5, do_junk());
    cout << "@@ list6" << endl;
    boost::fusion::for_each(list_test6, do_junk());
    cout << "@@ list7" << endl;
    boost::fusion::for_each(list_test7, do_junk());
    cout << "@@ joint_view1" << endl;
    boost::fusion::for_each(joint_view_test1, do_junk());
    cout << "@@ joint_view2" << endl;
    boost::fusion::for_each(joint_view_test2, do_junk());
    cout << "@@ joint_view3" << endl;
    boost::fusion::for_each(joint_view_test3, do_junk());
    cout << "@@ joint_view4" << endl;
    boost::fusion::for_each(joint_view_test4, do_junk());
    cout << "@@ joint_view5" << endl;
    //boost::fusion::for_each(joint_view_test5, do_junk());
    cout << "@@ joint_view6" << endl;
    //boost::fusion::for_each(joint_view_test6, do_junk());
    cout << "@@ joint_view7" << endl;
    //boost::fusion::for_each(joint_view_test7, do_junk());
    cout << "@@ joint_view8" << endl;
    //boost::fusion::for_each(joint_view_test8, do_junk());
    cout << "@@ joint_view9" << endl;
    //boost::fusion::for_each(joint_view_test9, do_junk());
    cout << "@@ joint_view10" << endl;
    //boost::fusion::for_each(joint_view_test10, do_junk());
    cout << "@@ joint_view11" << endl;
    boost::fusion::for_each(joint_view_test11, do_junk());
    cout << "@@" << endl;

    return 0;
}
开发者_Go百科


fusion::joint_view is holding on to it's elements as references. You need to be very careful it does not refer to temporaries (they would be gone out of scope at iteraton time in your setup). This seems to be the case in your examples.


I'm not 100% sure from the sample that it's what you're doing, but you generally cannot change the contents of a list while iterating through it, or else your iterator is invalid. Queue the list of items you would've added, then add them all in one go at the end.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜