2017-05-20 3 views
0

문제 사용 : 나는 캘린더 응용 프로그램에서 일하고 있어요

다음 unique_ptr더블 무료 또는 손상 unique_ptr 및 상속

설정을 덮어 쓰기 할 때 "더블 무료 또는 손상"로 충돌

합니다. 나는 sf::Drawable 클래스를 가진 SFML을 사용하고있다.
나는 DayView : public sf::Drawable 클래스와 WeekView : public sf::Drawable 클래스를 가지고 있습니다. 이 두 클래스는 달력 내용을 표시하기위한 구체적인 구현입니다. 1 일 현명한 1 주일 현명한.
클래스 CalendarScene에서 나는 단순히 클릭으로 대체 할 수있는 현재 구현에 대한 포인터를 갖고 싶습니다.
따라서 덮어 쓸 때 자동으로 삭제하려면 unique_ptr<sf::Drawable> displayImpl에 넣으십시오. 지금 나는 또한 중 하나의 구성원으로 shared_ptr<vector<shared_ptr<Calendar::Entry>>>이 버튼을을 눌러 메시지 *** Error in '/home/XXX/workspaces/CDT/XXX/Debug/XXX': double free or corruption (out): 0x0000000000f9ed60 ***

WeekView의 (virtual) 소멸자에 displayImpl = unique_ptr<DayView>(new DayView(...)) 응용 프로그램이 충돌을 재 할당하는 경우

는 지금은 displayImpl = unique_ptr<WeekView>(new WeekView(...))
를 할당 *View 클래스입니다. 이것이 역할을하는지 알지 못합니다.

어디에 내 문제가 있습니까?

코드

/* 
* CalendarScene.h 
* 
* Created on: 17. Nov. 2016 
*  Author: martin 
*/ 

#ifndef SCENES_CALENDARSCENE_H_ 
#define SCENES_CALENDARSCENE_H_ 

#include "../Scene.h" 
#include "../api/google/GoogleApi.h" 
#include "../api/Calendar.h" 
#include "../event/Event.h" 
#include <vector> 
#include <memory> 

class CalendarScene: public Scene { 
    public: 
     CalendarScene(GoogleApi * api); 
     virtual ~CalendarScene(); 

     void prepare(const sf::Vector2u size) override; 
     void event(Event &evt) override; 

    private: 
     void draw(sf::RenderTarget &, sf::RenderStates) const override; 
     sf::String texttodisplay; 

     std::vector<std::shared_ptr<Calendar>> calendars; 
     Calendar::Entries ents; 
     Json::Value calendarList; 
     Json::Value eventList; 

     enum { WEEK, DAY } displayMode; 
     int wOffset; 

     std::unique_ptr<sf::Drawable> displayImpl = nullptr; 

}; 

#endif /* SCENES_CALENDARSCENE_H_ */ 

/* 
* CalendarScene.cpp 
* 
* Created on: 17. Nov. 2016 
*  Author: martin 
*/ 

#include "CalendarScene.h" 
#include <SFML/Graphics.hpp> 
#include <algorithm> 
#include "../ui/SmartText.h" 
#include "../ui/UIFactory.h" 
#include "../util/sfmladditions.h" 

using std::unique_ptr; 
using std::shared_ptr; 
using std::runtime_error; 
using std::time; 
using std::time_t; 
using std::string; 

using io::curl::parameter_map; 

using Json::Value; 
using Json::ValueIterator; 

namespace { 

typedef shared_ptr<vector<shared_ptr<Calendar::Entry>>> SharedEntrySharedVector; 

enum Format { 
    PORTRAIT, LANDSCAPE 
}; 


class WeekView : public sf::Drawable { 
public: 
    WeekView(SharedEntrySharedVector weekEntries) : ents(weekEntries) {} 
    virtual ~WeekView() {} 
protected: 
    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; 
private: 
    SharedEntrySharedVector ents; 
}; 

class DayView : public sf::Drawable { 
public: 
    int dayOffsetToNow = 0; 

    DayView(SharedEntrySharedVector dayEnt) : ents(dayEnt) {} 

protected: 
    virtual void draw(sf::RenderTarget& target, sf::RenderStates) const; 
private: 
    SharedEntrySharedVector ents; 
}; 

void WeekView::draw(sf::RenderTarget& target, sf::RenderStates) const { 
    /* some drawing */ 
} 

void DayView::draw(sf::RenderTarget& target, sf::RenderStates) const { 
    /* some other drawing */ 
} 

} // namespace 

CalendarScene::CalendarScene(GoogleApi * api) : 
     Scene(api), displayMode(WEEK), wOffset(0), displayImpl(new WeekView(SharedEntrySharedVector())) { 
} 

CalendarScene::~CalendarScene() { 
    calendars.clear(); 
} 

/* 
* 
* Obtain calendar list 
* Obtain event list 
* 
*/ 
#include <iostream> 
void CalendarScene::prepare(const sf::Vector2u target) { 

    /* populating the ents.entries field which is of type vector<shared_ptr<Calendar::Entry>> */ 

    displayImpl = unique_ptr<WeekView>(new WeekView(SharedEntrySharedVector(&(ents.entries)))); 
} 

void CalendarScene::event(Event &evt) { 
    if (evt.type() == Event::Type::ScreenEvent) { 
     /* nothing interesting */ 
    } else if (evt.type() == Event::Type::ButtonEvent) { 
     ButtonEvent &b = (ButtonEvent&) evt; 
     switch (b.eventChar()) { 
     case sf::Keyboard::Key::W: 
      displayMode = WEEK; 
      displayImpl = unique_ptr<WeekView>(new WeekView(SharedEntrySharedVector(&(ents.entries)))); 
      break; 
     case sf::Keyboard::Key::T: 
      displayMode = DAY; 
/******** Here lies the problem ********/ 
      displayImpl = unique_ptr<DayView>(new DayView(SharedEntrySharedVector(&(ents.entries)))); 
      break; 
     case sf::Keyboard::Key::Right: 
      wOffset++; 
      break; 
     case sf::Keyboard::Key::Left: 
      wOffset--; 
      break; 
     default: 
      return; 
     } 
     if (wOffset < 0) 
      wOffset = 0; 
     else if (wOffset > 6) 
      wOffset = 6; 
     if (displayMode == DAY) { 
      ((DayView*)displayImpl.get())->dayOffsetToNow = wOffset; 
     } 
    } 
} 

void CalendarScene::draw(sf::RenderTarget &target, sf::RenderStates) const { 
    if (!displayImpl) 
     return; 

    target.draw(*displayImpl); 
} 

Valgrind의 말한다 :

==27630== Invalid free()/delete/delete[]/realloc() 
==27630== at 0x4C2A360: operator delete(void*) 
==27630== by 0x4B6D4D: std::_Sp_counted_ptr<std::vector<std::shared_ptr<Calendar::Entry>, std::allocator<std::shared_ptr<Calendar::Entry> > >*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() 
==27630== by 0x411665: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() 
==27630== by 0x41054A: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() 
==27630== by 0x4ABDC9: std::__shared_ptr<std::vector<std::shared_ptr<Calendar::Entry>, std::allocator<std::shared_ptr<Calendar::Entry> > >, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() 
==27630== by 0x4ABE51: std::shared_ptr<std::vector<std::shared_ptr<Calendar::Entry>, std::allocator<std::shared_ptr<Calendar::Entry> > > >::~shared_ptr() 
==27630== by 0x4A461E: (anonymous namespace)::WeekView::~WeekView() 
==27630== by 0x4A46B3: (anonymous namespace)::WeekView::~WeekView() 
==27630== by 0x4AE161: std::default_delete<sf::Drawable>::operator()(sf::Drawable*) const 
==27630== by 0x4AF7BD: std::unique_ptr<sf::Drawable, std::default_delete<sf::Drawable> >::reset(sf::Drawable*) 
==27630== by 0x4AB181: std::enable_if<std::__and_<std::is_convertible<std::unique_ptr<(anonymous namespace)::DayView, std::default_delete<(anonymous namespace)::DayView> >::pointer, sf::Drawable*>, std::__not_<std::is_array<(anonymous namespace)::DayView> > >::value, std::unique_ptr<sf::Drawable, std::default_delete<sf::Drawable> >&>::type std::unique_ptr<sf::Drawable, std::default_delete<sf::Drawable> >::operator=<(anonymous namespace)::DayView, std::default_delete<(anonymous namespace)::DayView> >(std::unique_ptr<(anonymous namespace)::DayView, std::default_delete<(anonymous namespace)::DayView> >&&) 
==27630== by 0x4AA445: CalendarScene::event(Event&) 
==27630== by 0x4DC982: ClientWatch::ClientWatchPrivate::runWindowed() 
==27630== by 0x4DC6AE: ClientWatch::ClientWatchPrivate::run() 
==27630== by 0x4DC758: ClientWatch::run() 
==27630== by 0x529CE7: main 
==27630== Address 0xeb334b0 is 48 bytes inside a block of size 176 alloc'd 
==27630== at 0x4C29180: operator new(unsigned long) 
==27630== by 0x4E0904: _ZN11ClientWatch18ClientWatchPrivate9makeSceneI13CalendarSceneIRP9GoogleApiEEESt10unique_ptrI5SceneSt14default_deleteIS7_EEDpOT0_ 
==27630== by 0x4DF88E: _ZN11ClientWatch18ClientWatchPrivate8newSceneI13CalendarSceneIRP9GoogleApiEEEvDpOT0_ 
==27630== by 0x4DD519: ClientWatch::ClientWatchPrivate::drawFrame() 
==27630== by 0x4DCB36: ClientWatch::ClientWatchPrivate::runWindowed() 
==27630== by 0x4DC6AE: ClientWatch::ClientWatchPrivate::run() 
==27630== by 0x4DC758: ClientWatch::run() 
==27630== by 0x529CE7: main 
==27630== 

shared들에 unique_ptr의 변경하는 것은 도움이되지 않습니다. 여전히 이중 자유 오류.

+3

코드에 문제가 없습니다. 당신이 보여 줬어. [mcve]를 만드십시오. 또한'std :: make_unique' 사용을 고려하십시오. – nwp

+1

SFML에는 자체 소유권 체계가 있습니까? – Angew

+0

@nwp 코드는 MVCE가 아니지만 처음부터 다시 시도하고 오류가 발생하지 않았습니다. 그래서 간단히 코드를 붙여 넣었습니다. 오류가있는 곳을 찾을 수 없다는 단서가 없습니다. –

답변

2

이 개체를 복사하여 다른 곳에 삭제했을 수도 있습니다. std :: unique_ptr <> 언급 한 사례를 처리 할 수 ​​있어야합니다. 예를 들어 이것을 가지고, 그것을 잘 작동합니다 : 당신이 포인터를 가지고 다른 unique_ptr에 할당하면

#include <memory> 
#include <iostream> 

struct A { 
    int a; 
    A(int v) : a(v) {} 
}; 

int main() { 
    std::unique_ptr<A> p(new A(1)); 
    p = std::unique_ptr<A>(new A(3)); 
    std::cout << "A:" << p->a << "\n"; 
    return 0; 
} 

그런 다음 당신은 두 배를 얻을 수

int main() { 
    std::unique_ptr<A> p(new A(1)); 
    std::unique_ptr<A> q(p.get()); 
    std::cout << "A:" << p->a << "\n"; 
    return 0; 
} 

처럼, 그러나

$ clang++ -std=c++11 testUniquePtr.cpp -o testUniquePtr 
$ ./testUniquePtr 
A:3 

을 실행 무료 :

$ ./testUniquePtr 
A:1 
*** Error in `./testUniquePtr': double free or corruption (fasttop): 
0x0000000001258c20 *** 
======= Backtrace: ========= 
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f1ce28367e5] 
/lib/x86_64-linux-gnu/libc.so.6(+0x7fe0a)[0x7f1ce283ee0a] 
+0

이라는 probem이 나타납니다. 새로운 객체로 새로운 unique_ptrs를 생성하기 만하면됩니다 ... 의심 스럽습니다. 문제가 ... –

+0

이 특정 변수가 아닌 다른 곳에서 손상이 발생할 가능성이 있습니다. 그것은 일반적인주의 산만입니다. 'valgrind --mem-check = full '로 응용 프로그램을 실행하고 이전 오류를 확인하십시오. '-o0 -ggdb3'으로 컴파일하면 도움이됩니다. –

+0

느슨하게 가서 std :: unique_ptr을 std :: shared_ptr로 바꾸고 무슨 일이 일어나는 지보십시오. 때로는 변경 사항이 붙어있을 때 특히 합리적인 것이 아니더라도 솔루션으로 이동할 가능성이 있습니다. –