Я делаю игру с SDL, которая использует libconfig для чтения некоторых настроек из файла. Проблема в том, что я сделал класс под названием ClipList
который содержит std::vector<SDL_Rect>
сохранить настройки, но при попытке добавить SDL_Rect
объекты по вектору, по какой-то причине push_back ничего не делает, и я получаю пустой вектор.
Это класс:
class ClipList
{
public:
ClipList();
ClipList(int);
virtual ~ClipList();
void addClip(int,int,int,int);
void getClip(int,SDL_Rect*);
int getLength();
protected:
private:
std::vector<SDL_Rect> clips;
};
ClipList::ClipList(int l)
{
clips.reserve(l);
}
void ClipList::addClip(int x,int y,int w,int h){
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
clips.push_back(rect);
}
void ClipList::getClip(int i,SDL_Rect* rect){
rect = &(clips.at(i));
}
int ClipList::getLength(){
return clips.size();
}
И это функция, где я инициализирую объект ClipList. Эта функция вызывается из main.
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips){
const Setting& root = placlips->getRoot();
int x,y,w,h;
try{
Setting& clipsett = root["clips"];
int cliplen = clipsett.getLength();
clips = new ClipList(cliplen);
flipclips = new ClipList(cliplen);
for(int i=0;i<cliplen;i++){
const Setting& c = clipsett[i];
if(!(c.lookupValue("x",x)&&c.lookupValue("y",y)&&c.lookupValue("w",w)&&c.lookupValue("h",h))){
continue;
}
clips->addClip(x,y,w,h);
}
}catch(const SettingNotFoundException &nfex){
cerr << "Setting not found at" << nfex.getPath() << endl;
}
}
Независимо от того, ClipList
объекты инициализируются в main
или же set_clips
, clips.push_back(rect)
не работает Емкость вектора изменяется, но никакой объект не сохраняется, поэтому я получаю segfault, если пытаюсь сделать что-то еще с вектором, даже проверяя, является ли вектор пустым или нет.
Я собираюсь угадать, подпись функции
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips);
виновник Вы выделяете память для clips
а также flipclips
в этой функции, но так как указатели передаются по значению, вызывающая функция не видит выделенную память.
Если вы измените сигнатуру функции на:
void set_clips(Config* placlips, ClipList*& clips, ClipList*& flipclips);
ваши проблемы должны уйти.
clips.push_back(rect)
работает нормально. Ваш set_clips
функция выделяет новые экземпляры ClipList, но не передает эти указатели вызывающей стороне. Вызывающий, вероятно, пытается использовать указатель мусора в качестве экземпляра инициализации, и именно поэтому вы получаете segfault.
Вам необходимо передать созданные объекты обратно. Вы должны использовать что-то вроде std :: shared_ptr<> Для этого вместо голых указателей.
Обновление о том, как сделать это без использования std :: shared_ptr<>:
Вы должны следить за собственностью и иметь дело с исключениями. С точки зрения фактической передачи, правило, которое я использую (первоначально от Lakos в «Large Scale C ++ Software Design»), заключается в том, что параметры, которые являются возвращаемыми значениями (как вы пытаетесь их использовать), являются указателями, а параметры только для чтения — значение или const-ссылка. Возвращаемые значения идут первыми.
Так что ваши set_clips
функция должна выглядеть так:
void set_clips(ClipList** clips, ClipList** flip_clips, Config const& placlips)
Когда вы звоните set_clips
вы передаете указатель на каждый указатель, который получит выделенное значение, и передаете const-ссылку на объект placlips, который не изменяется функцией.
Вы бы все это примерно так
ClipList* clips = 0;
ClipList* flip_clips = 0;
set_clips(&clips, &flip_flips, placlips);
// ... then do whatever comes next.
Но объединяя эти правила с std :: shared_ptr<> или повысить :: shared_ptr<> Лучше и стиль «современный C ++».