2010-10-13 1 views
2

Редактировать: Это оказалось проблемой во временном порядке. В принципе, я не знал использовать C++, как если бы он работал как Java или C#, чего нет. Надеюсь, это будет хороший предостерегающий рассказ.Boost Fusion контейнер общих указателей (shared_ptr), вызывающий ошибку сегментации (sigsegv) или результаты мусора

Редактировать: Эта проблема возникает только с комбинацией joint_view и shared_ptr. Очевидно, что исходные указатели работают в одном и том же сценарии, как и общие указатели в обычном контейнере слияния, сконструированном со всеми его элементами одновременно, не добавляя к нему ничего большего. Подробности ниже:

Я использую MinGW GCC 4.5.1 Запуск в своеобразный вопрос при использовании наддува фьюжн контейнера (ов) и получить содержимое обратно. У меня есть пользовательский класс, который обернут в std::shared_ptr, тогда это передано fusion make_list() (или make_vector(), похоже, не имеет значения). Все хорошо, если я могу одновременно забрать все свои объекты в контейнер. Проблема, похоже, возникает, когда я добавляю еще один общий указатель на контейнер, который дает joint_view. Я повторяю с помощью fusion::for_each() и передаю объект функции, чтобы распечатать значение. Если я повторяю обычный контейнер слияния общих указателей вместо joint_view или joint_view без общих указателей в нем, он отлично работает, но в остальном - ошибки сегментации или значения мусора.

Ниже приведена тестовая программа, которую я сделал, чтобы попытаться изолировать мою проблему. Любые идеи о том, что может быть проблемой? Это вполне возможно, я просто не хватает что-то, что я должен/не должен делать :(

#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; 
} 

ответ

4

fusion::joint_view держит на это элементы в качестве ссылок. Вы должны быть очень осторожны, чтобы они не ссылались на временные (они были бы недоступны во время итерации в вашей настройке). Это похоже на ваши примеры.

+0

Правильно, я понимаю метод joint_view для хранения его элементов и полагаю, что я могу потерять временные ряды, но именно поэтому у меня так много тестов с использованием 'shared_ptr' чтобы обернуть элементы, входящие в контейнер. И снова, если я получу все предметы в контейнере за один раз и не использую 'push_back()', чтобы добавить что-либо, он отлично работает. Кроме того, если вы посмотрите на joint_view_test3, я не использую 'shared_ptr', но я добавляю еще один элемент, и он отлично работает. Это когда у меня есть контейнер 'shared_ptr' и добавьте еще что-то к нему, а затем подайте полученный файл joint_view в 'for_each(), что у меня проблемы. –

+1

Что вы думаете? Для меня очевидно, что вы создаете временные разделы, которые привязаны к ссылкам внутри joint_view. Не пытайтесь сохранить файл joint_view, но напрямую передавайте его функции, которая должна что-то с ней делать. Это предотвратит слишком быстрое выключение временных рядов.Прочитайте в стандарте, если вы не знаете, как долго временные файлы хранятся в компиляторе (подсказка: обычно до следующей точки с запятой, но это только приблизительная оценка). – hkaiser

+0

Похоже на то, что вы сказали немного ... Я добавил еще один тестовый пример, и это сработало, и я понимаю, почему это сработало, но я все еще немного потерян, поэтому, пожалуйста, несите меня. Да, я создавал temps, но обертывал их в интеллектуальные указатели и предоставлял их контейнеру слияния, сам по себе был temp. Но до того, как контейнер выходит из области видимости, я добавляю к нему еще одну ptr-wrapped temp, создавая 'joint_view', который содержит ссылки на ... мои умные указатели (мое предположение)? Или у него есть ссылки на элементы за моими умными указателями? Если он удаляет мои указатели, я понимаю, что мои объекты выходят за рамки. –

0

Я не уверен на 100% из образца, что это то, что вы делаете, но вы, как правило, не может изменить содержимое списка во время прохода через него, или же ваш итератор недействителен. Очередь список элементов, которые бы уже добавил, а затем добавить их все за один раз в конце.

+0

Ну, я ничего не меняю во время итерации, просто печатая значения того, что должно быть в контейнере Fusion, поэтому я не думаю, что это так. Согласно документам Fusion (если я читаю их правильно), выполнение push_back не изменяет contianer Fusion. Вместо этого Fusion создает представление, указывающее на контейнер Fusion и любые новые объекты, которые вы «добавляете» к нему, а for_each выполняет итерацию для вас, передавая каждый элемент в контейнер в объект функции, который вы предоставляете. –

+0

Кроме того, объекты очередей разных типов именно поэтому я использую контейнер Fusion. Но из-за этой проблемы я не могу получить обратно то, что я вставляю. –

 Смежные вопросы

  • Нет связанных вопросов^_^