2014-02-28 4 views
5

, 그것은 클래스 Foo 회원으로 클래스 Bar이있는 경우, 이제 scope를 사용하여 스택에 즉D에서 개체가 내부적으로 구성원 개체를 보유 할 수 있습니까? D에서

void foo() 
{ 
    scope example = new Bar(); 
} 

를 클래스를 할당하는 것이 가능, Foo 내부에서 적절한 Bar를 저장하고있을 수있는 방법이있다 그것은 Foo 라 C++로 해체됩니까?

은 내가 메인이야

import std.stdio; 

class Foo { 
    this() { writeln("Foo"); } 

    ~this() { writeln("~Foo"); } 

    scope Bar inside; 
} 

class Bar { 

    this() { writeln("Bar"); } 

    ~this() { writeln("~Bar"); } 
}; 

void main() 
{ 
    scope f = new Foo(); 
    writeln("I'm a main!"); 
} 



같은 것을 얻을 것이라고 기대했다!
~ 바
~ 푸

대신에 나는 단지 내가 메인이야

에게 푸
를 얻을!
~ 푸

그것은 가비지 수집 참조로 클래스 멤버를 저장하는 대신에 적절한 다만 불필요하게 작은 이익을 위해 힙 레이아웃을 복잡처럼 보인다. 이 경우 scope은 무엇입니까? Bar을 제자리에서 유지하도록 지정하지 않으면 어떻게됩니까?

답변

5

범위 클래스를 사용하지 마십시오. 그것들은 효과적으로 더 이상 사용되지 않으며 옛날의 유산으로 만 남아 있습니다. 비슷한 효과를내는 Phobos helper가 있습니다. 귀하의 예를 다시 작성 :

import std.stdio; 
import std.typecons; 

alias ScopedBar = typeof(scoped!Bar()); 

class Bar { 

    this() { writeln("Bar"); } 

    ~this() { writeln("~Bar"); } 
}; 

class Foo 
{ 
    this() 
    { 
     this.inside = scoped!Bar(); 
     writeln("Foo"); 
    } 

    ~this() { writeln("~Foo"); } 

    ScopedBar inside; 
} 

void main() 
{ 
    writeln("Main before scope"); 
    { 
     auto f = scoped!Foo(); 
    } 
    writeln("Main after scope"); 
} 
0

사용자가 해당 클래스의 인스턴스를 만들지 않았기 때문에 Bar~Bar을 얻지 못합니다.

+0

그 말은하지 않는 것 같습니다. 나는 'scope bar inside'가 그 효과를 가지기를 기대했지만, 'Foo'의 멤버 인 Bar를 참조하는 것으로 보인다. 그 맥락에서'정적'은 무엇을 하는가? 내가 성취하려는 일을하는 방법이 있습니까? –

2

Bar이 구조체 인 경우 범위가 필요하지 않고 원하는 것을 얻을 수 있습니다. 단, 구조체에는 기본 생성자가 없을 수 있으므로 은 허용되지 않습니다. 인터페이스와 가상 함수가 필요하지 않다면 구조체가 더 유연하기 때문에 일반적으로 구조체가 D에서 사용하는 더 나은 도구라고 생각합니다. 결정적 파기, 간접 지정 등이없는 범위 구조체를 매우 쉽게 가질 수 있습니다. 참조가되도록하려면 참조 구조를 강제하기 위해 항상 내부 구조체에 대한 포인터 또는 포인터를 사용할 수 있습니다.

은 현재 위치에서 할당을 포함하여 구조체에서 클래스를 래핑 할 수 있습니다 :

import std.stdio; 

// bar is first because of https://d.puremagic.com/issues/show_bug.cgi?id=12278 
class Bar { 
    this() { writeln("Bar"); } 
    ~this() { writeln("~Bar"); } 
} 


class Foo { 
    this() { 
     writeln("Foo"); 
     // since there's no default ctor for structs, we force 
     // initialization right here 
     inside = InPlace!Bar.getDefault(); 
    } 

    ~this() { writeln("~Foo"); } 

    // InPlace instead of scope... 
    InPlace!Bar inside; 
} 

struct InPlace(T) { 
    // an in-place buffer for the class data... 
    private byte[__traits(classInstanceSize, T)] rawData; 

    @property T obj() { return cast(T) rawData.ptr; } 
    alias obj this; // DANGER: don't escape this reference! 
    @disable this(); // force initialization at the usage site 

    // get it default-constructed 
    static InPlace!T getDefault() { 
     InPlace!T t = void; 
     t.initializeObject(); 
     t.obj.__ctor(); 
     return t; 
    } 

    void initializeObject() { 
     assert(__traits(classInstanceSize, T) == 8); 
     assert(T.classinfo.init.length == 8); 
     assert(this.rawData.length == 8); 
     this.rawData[] = T.classinfo.init[]; 
    } 

    // ctors with args 
    this(T...)(T t) { 
     initializeObject(); 
     obj._ctor(t); 
    } 
    ~this() { 
     .destroy(obj); // call the class destructor in the struct dtor 
    } 
} 

void main() 
{ 
    scope f = new Foo(); 
    writeln("I'm a main!"); 
} 

편집 : std.typecons.scoped 내가 그것을 클래스에서 일하는 것이 확실하지 않았다,도이 작업을 수행 회원하지만 Михаил Страшун의 대답은 실제로 그것을 보여 주었다./편집

그 트릭을 할 것입니다 ...하지만 나는 그것에 대해 권장합니다. 가능한 경우 바 자체를 구조체로 만들어야합니다. 이 래퍼 마법의 위험은 내부 객체에 대한 참조를 벗어나면 외부 객체가 먼저 파괴되면 무작위 적으로 충돌 할 가능성이 있습니다. 사적인 것이라해도 괜찮은 가봐야 할 것 같아. (D의 개인은 이다. 모듈은이다. 그래서 그 모듈의 다른 기능은 여전히 ​​그것을 피할 수있다. 그러나 여전히 충분히주의해야한다. 그것으로 괜찮을 수 있습니다.)

러닝주는 : 푸 바 전 메인! ~ Foo ~ 바

BTW OP에서 사용하는 범위는 현재 안전하지 않거나 완벽하게 구현되지 않았기 때문에 현재 사용되지 않습니다. 나는 심지어 스택을 할당한다고 생각하지 않는다. 바로 뒤에 선언문 바로 뒤에 scope(exit) .destroy(foo);을 삽입하는 것과 같다.

+0

Scoped! T 구조체가 왜 숨겨져 있는지 궁금하다. (별칭의 해결 방법을 강요한다.) –

+0

내 생각에 함수 - 로컬 범위 (또는 단지 voldemort 유형이 과용되고 있음을 알지 못한다; 나는 공개적으로 사용할 수 있다고 생각한다. 전에 Scoped! T를 사용하는 것을 기억하는 것 같습니다. –

+0

DPaste에서이 코드를 컴파일하는 중 오류가 발생합니다. http://dpaste.dzfl.pl/d659656fac86 – DejanLekic