당신은 이미이 모든 것을 알고있을 것입니다. 그러나 이것은 약간의 FAQ이므로 약간의 세부 사항을 작성하려고합니다.
먼저, 대리인이 무엇인지 이해해 봅시다. 슬라이스가 길이와 쌍을 이루는 C 데이터 포인터 인 것처럼, 델리게이트는 함수 포인터와 쌍을 이루는 C 데이터 포인터 일뿐입니다. 이
struct d_delegate {
void* ptr; // yes, it is actually typed void*!
T* funcptr; // this is actually a function pointer
};
정의 된 것처럼 이들은, 그들에게 기대하는 기능과 함께 전달된다 (중첩 된 위임을 할 때 일부 컴파일러 오류 뒤에 이유가 단지 하나의 데이터 PTR 있다는 사실합니다 !이 시점에서
Object obj = new Object();
string delegate() dg = &obj.toString;
,-dg.ptr
포인트 : 슬라이스 void*
데이터를 가리키는 것입니다
그건) 클래스 메소드 내에서와 마찬가지로 다양한 장소에서 올 수, 가비지 수집 클래스 개체가 발생하지만, 그 이유는 내가 위에 new
그것을 편집했기 때문입니다. 이 경우
struct MyStruct {
string doSomething() { return "hi"; }
}
MyStruct obj;
string delegate() dg = &obj.doSomething;
인해 dg.ptr
는 또한 임시 개체를 가리 키도록 내가 위를 할당하는 방법을 스택에 obj
살고있다.
무언가가 위임자이든 아니든간에 사용 된 메모리 할당 체계에 대해 아무 말도하지 않습니다. 전달 된 대리자가 끝내기 전에 사라질 임시 개체를 가리킬 수 있으므로 틀림없이 위험합니다. (그런 이유로 GC가 그런 사용 후 자유로운 버그를 방지하는 데 도움이되는 주된 이유입니다.)
따라서 어떤 대리인이 어떤 객체에서 왔는지 알 수있는 이유는 무엇입니까? 음, 자동으로 생성 된 클로저는 컴파일러가 델리 게이트의 수명이 외부 함수보다 길다고 생각할 때 로컬 변수를 GC 세그먼트에 복사 할 수 있습니다.여기
void some_function(void delegate() dg);
void foo() {
int a;
void nested() {
a++;
}
some_function(&nested);
}
, 그것의 복사본을 보관합니다 some_function
을 가정하고 처리 할 때 use-after-free 고통이다 버그 (방지하고자하기 때문에 GC 세그먼트에 변수 a
을 복사합니다 컴파일러는 자주로 디버깅하는 방법 메모리 손상을 유발합니다!)뿐만 아니라 메모리 누수가 발생합니다. 당신은 당신이 대리자 정의에 scope
키워드를 사용하여 스스로를 잘 할 것 컴파일러를 약속 경우
그러나, 당신을 신뢰하고 그들이 어디에 바로 지역 주민을 떠나 :
void some_function(scope void delegate() dg);
상태 유지 나머지는 동일하게, 더 이상 사본을 할당하지 않습니다. 함수 정의 측면에서 수행하는 것이 가장 좋습니다. 함수 작성자는 실제로 사본을 보관하지 않을 수 있기 때문입니다. 지역 변수의 주소가 중첩 된 기능에 의해 사용되는 경우
void foo() {
int a;
void nested() {
a++;
}
// this shouldn't allocate either
scope void delegate() dg = &nested;
some_function(&dg);
}
그래서, 유일한 시간 메모리가 자동으로 GC에 의해 할당된다
하지만 사용 측면에서
, 당신은 또한 그것의 범위에 레이블을 지정할 수 있습니다 없이scope
키워드를 가져 왔습니다.
() => whatever
및 () { return foo; }
구문은 주소가 자동으로 지정되는 명명 된 중첩 된 함수의 단순한 축약이므로 위와 같은 방식으로 작동합니다. dg = {a++;};
은 위의 dg = &nested;
과 동일합니다.
따라서 위임자가 수동으로 할당하려는 경우 변수를 자동으로 캡처하는 대신 수동으로 개체를 할당하고 해당 메서드 중 하나에서 대리인을 만들어야합니다. 그러나 평생을 추적하고 올바르게 해제해야합니다. 그것은 까다로운 부분입니다. 당신 그래서 예를 들면
: 당신이 돈 그렇게 할 때
struct Helper {
T res;
void del() {
cell.write(res);
}
}
Helper* helper = malloc(Helper.sizeof);
helper.res = res; // copy the local explicitly
send(&helper.del);
그런 다음, 수신 측에 free(dg.ptr);
하는 것을 잊지 마세요 :
이
auto del =() {
let res = f();
cell.write(res);
};
당신이이로 번역 할 수 그것을 유출하지 마십시오.
send
을 실제로 Helper
개의 객체로 변경하면 더 이상 할당 할 필요가 없습니다. 값으로 전달할 수 있습니다.
또한 당신이 자리에서 다른 데이터를 전달하기 위해 그 포인터에 다른 데이터를 포장 할 수 있지만,이 ABI 해킹 및 정의되지 않은 행동이 될 거라고 나에게 발생합니다. 비록 당신이 원한다면 그것을 시도하십시오 :)
위대한 설명 감사. –