2016-05-31 2 views
-1

У меня есть программа на C++, как показано ниже. Я пытаюсь передать std :: list из одной функции в другую по значению. Я ожидаю, что список будет доступен в функции вызывающего абонента с помощью итератора? Я ожидаю, что возврат вызовет конструктор копирования std::list, и он будет доступен в вызывающем. Я ошибаюсь в своем предположении? Если нет, то почему я получаю ошибку сегментации.Передача std :: list из одной функции в другую по значению

#include <list> 
#include <map> 
#include <string> 
#include <set> 
#include <iterator> 
#include <iostream> 

const char *sy_path = "/var/log"; 
struct Setting 
{ 
    typedef std::list<const Setting*> List; 

    const char*  path; 
    const char*  filename; 
    const char*  name; 

    int def; 
    int min; 
    int max; 

    struct Original 
    { 
     const char*  filename; 
     const char*  name; 

     Original(const char* filename_, const char* name_) 
        :filename(filename_), name(name_) 
     { 

     } 
    }original; 
    static const List settings(); 
}; 

const Setting::List Setting::settings() 
{ 
    const Setting c_settings[] = 
    {              //default min max  
     { sy_path, "cs.cfg",  "num_a",     1, 1, 29,   Original("sys.cfg", "num_a") } 
     ,{ sy_path, "cs.cfg",  "num_b",     1, 1, 6,    Original("sys.cfg", "num_b") } 
     ,{ sy_path, "cs.cfg",  "num_c",     1, 1, 29,   Original("sys.cfg", "num_c") } 
    }; 

    Setting::List lst; 

    int numelem = sizeof(c_settings)/sizeof(Setting); 
    for (int i = 0; i < numelem; i++) 
    { 
     const Setting & tmpSetting = c_settings[i]; 
     lst.push_back(&tmpSetting); 
    } 

    return lst; 
} 

static int get_settings(void) 
{ 
    Setting::List lst; 
    lst = Setting::settings(); 

    for (Setting::List::const_iterator it = lst.begin() ; it != lst.end(); ++it) 
    { 
     const Setting *cs = *it; 
     std::cout << "path: " <<cs->path << "filename: " <<cs->filename << "name: " << cs->name << std::endl; 
    } 
} 

int main() 
{ 
    get_settings(); 

    return 0; 
} 
+0

Вы возвращаете список указателей на данные, которые уже давно разрушены, прежде чем вы выполните его в 'get_settings'. Попробуйте вместо этого изменить список на 'std :: list '. – fbrereto

+1

Почему, почему, почему? Не проблема, но почему многие люди пишут назначения вместо инициализации? 'Setting :: List lst; lst = Setting :: settings(); 'должно быть' Setting :: List lst = Setting :: settings(); '. Нет причин создавать объект List и немедленно выбросить его. –

ответ

1

Да, return lst; возвращает копию lst. Проблема в том, что вы помещаете указатели lst в данные, расположенные в стеке (переменная const Setting c_settings[]). Эти указатели становятся недействительными после того, как вы вернетесь из функции, следовательно, с ошибкой сегментации. Решение состоит в том, чтобы либо выделить память для ваших настроек в куче, либо использовать std::list<Setting>.

typedef std::list<Setting> List; 

lst.push_back(c_settings[i]); // make sure you have the right copy constructor 

или

lst.push_back(new Setting(c_settings[i])); // make sure you have the right copy constructor 

Кроме того, я хотел бы избежать использования const char * и использовать std::string вместо этого.

+0

Вы называете 'path',' filename', 'name' и т. Д., Который является' const char * '? И как вы относитесь к std :: list ? – liv2hak

+0

Я считаю, что вы в безопасности с путём, именем файла, именем, в этом случае, поскольку вы инициализировали их строковыми литералами (не знаю о sy_path). Однако '' 'c_settings''' создает 3 элемента установки локально для этой функции (и в стеке), поэтому они уходят при возврате из функции. По '' 'std :: list ' '' Я имею в виду сделать список не указателей, а установить элементы. – kaspersky

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