2014-03-26 3 views
1

나는 그때 호출 된 객체를 반환하는 하나의 팩토리 함수를 내보내는 모듈 (dll/so)을 가지고있다. 인터페이스 (순수 가상)를 사용하면 모듈의 사용자가 다른 객체를 만들 수 있습니다. 모든 객체 생성은 인터페이스를 통해 이루어 지므로 응용 프로그램 런타임이 아닌 내 모듈과 관련된 런타임을 사용하여 수행됩니다.Disallow/Redirect C++ delete?

할당이 모듈 내부에서 일어나므로 응용 프로그램이 내 모듈과 다른 런타임 인 ​​gpf/segfault 시간을 가지므로 삭제도 필요합니다. 그래서 나는 스스로 삭제를 수행하는 "release"멤버를 가지고있다.

void foo::release(void) 
{ 
    delete this; 
} 

모든 것이 잘 작동하지만 모듈 사용자가 작동해야합니다.

내 질문은 :

  • 그것은 바로 내 개체를 삭제 발행 사람을 중지 (또는 내 모듈 메모리 풀에서 삭제를 재) 할 수 있습니까?
  • 백업 계획이 아니라면 내 개체에서이를 감지 할 수 있습니까? 그렇다면 좋은 행동을 강요하는 단정을 던질 수 있습니까?

예컨대 : 편집에

iFoo* foo = createFoo(); 
foo->release();   // Allowed and expected 
delete foo;    // Disallowed 
+7

"개인용 소멸자 만들기"옵션을 고려 했습니까? – dave

+1

행동하지 않기로 선택한 사용자는 여러 가지 방법으로 당신을 깰 수 있습니다.인터페이스를 사용하기 쉽고 잘못 사용하기 어렵게 만들고 악의적 인 의도에 대해 너무 걱정하지 마십시오. –

+0

아마 스마트 포인터를 반환하는 순서입니까? http://en.wikipedia.org/wiki/Smart_pointer – amdn

답변

1

, @ 데이브는 protected 대신 public로 당신의 순수 인터페이스에서 소멸자를 선언하는 제안을했다. 이것은 외부 코드 (즉, 구현 클래스의 외부)가 delete을 호출하는 것을 완전히 차단합니다. 예를 들어

: 당신의 공장 기능은 순수한 인터페이스를 노출하기 때문에 구현 클래스 공개 소멸자를 제공하기 위해 발생하는 경우

class IFoo 
{ 
protected: 
    virtual ~IFoo() { } 

public: 
    virtual void release() = 0; 
}; 

class Foo : public IFoo 
{ 
public: 
    void release() override 
    { 
     delete this; 
    } 
}; 

IFoo* createFoo() 
{ 
    return new Foo(); 
} 

int main() 
{ 
    auto foo = createFoo(); 
    foo->release(); // Expected 
    delete foo;  // Cannot access protected destructor of IFoo 

    Return 0; 
} 

,이 방법은 분해되지 않습니다. Foo이 공용 소멸자를 선언하면 main에 컴파일러 오류가 발생합니다. main은 실제로 Foo을 처리하고 있다는 것을 모르기 때문입니다.

+0

안녕 Lilshieste, 데모 용 thx. 나는 이것이 내가 필요한 해결책이라고 생각한다. 한 가지 궁금한 점이 있습니다. 가상 소멸자가 컴파일러가 오류를 선택하기 위해 인터페이스 파일에 있어야합니까? 나는 그것을 알 수 있기 때문에 그것이 될 것이라고 추측하고 있습니다. 또한 나는 같은 사람으로부터 한 가지 이상의 대답을 게시하는 것을 허용하지 않았다. 청초한, 응. – Chris

+0

@Chris 처음에는 다른 답변 (Meta 사이트를 확인해야 함)을 올릴 수 있는지 몰랐습니다. 그리고 당신은 맞습니다 - 가상 소멸자가 모든 것이 제대로 작동하기 위해서는 인터페이스 파일에 있어야합니다. – Lilshieste

0

: 사용자가 리소스를 삭제하는이 방식은 더 어려워 - 그것은 명백한을 방지하지 않습니다. (유용 할 수도 있기 때문에이 답변을 삭제하지 마십시오.)

다른 사람이 내 개체에서 delete를 호출하지 못하도록하려면 다른 사람이 개체에서 delete를 호출하지 못하도록하려면 해당 사용자가 삭제하도록 요청하는 것은 불법입니다. 공장 기능.

값 유형은 실제 객체를 감싸는 얇은 래퍼 일 수 있으며 포인터 의미, 즉 스마트 포인터를 제공 할 수 있습니다.

거친 예 :

class IFoo 
{ 
public: 
    virtual ~IFoo() { } 

    virtual void release() = 0; 
}; 

class Foo : public IFoo 
{ 
public: 
    Foo() { } 

    void release() override 
    { 
     delete this; 
    } 
}; 

// Value type with pointer semantics 
template <class T> 
class Undeletable 
{ 
private: 
    T* m_resource; 

public: 
    Undeletable(T* resource) 
     : m_resource(resource) 
    { 
    } 

    T* operator->() 
    { 
     return m_resource; 
    } 
}; 

// Old factory function 
IFoo* createFoo() 
{ 
    return new Foo(); 
} 

// New factory function 
Undeletable<IFoo> createSafeFoo() 
{ 
    return Undeletable<IFoo>(createFoo()); 
} 

int main() 
{ 
    auto foo = createFoo(); 
    foo->release(); // Expected 
    delete foo;  // Possible but DO NOT WANT 

    auto safeFoo = createSafeFoo(); 
    safeFoo->release(); // Expected 
    delete safeFoo;  // Compiler says NOPE 

    return 0; 
} 

불행하게도, 이것은 단지 사용자가 여전히 리소스를 삭제 할 수 있다는 사실을 모호하게. 예를 들어 영업에 코멘트에서

delete safeFoo.operator->(); // Deletes the resource