2016-08-05 3 views
2

C++에서와 같이 구조체 복사 생성자를 명시 적으로 호출 할 수 있습니까? 다음과 같이 쓸 수 있습니까?D 구조 복사 생성자

struct foo { 
    void bar() {} 
} 

foo f; 
foo(f).bar(); 

또는 일부 varialbe에 항상 새 값을 할당해야합니까?

답변

6

기술적으로 D에는 복사 생성자가 없습니다. 오히려 구조체는 후미 생성자를 가질 수 있습니다. 예 :

struct S 
{ 
    this(this) 
    { 
    } 
} 

일반적으로 D는 구조체를 최대한 이동하고 복사하지 않습니다. 그리고 그것들을 복사 할 때 struct의 비트 복사를 수행 한 다음 postblit 생성자 (있는 경우)를 실행하여 비트 복사본 이상으로 수행해야하는 작업을 수행 한 후에 struct를 변경합니다. 당신이 회원

struct S 
{ 
    this(this) 
    { 
     if(i !is null) 
      i = new int(*i); 
    } 

    int* i; 
} 

복사 생성자 (C에서 ++)의 전체 복사본을 원하는 경우,/다른 한편으로는, 새로운 구조체/클래스를 구성하고 구조체에 해당 부재의 사본과 함께 각 멤버를 초기화 클래스 또는 복사 생성자의 초기화 프로그램 목록에서 초기화 된 것과 함께 복사됩니다. 그것은 D의 사후 생성자 (postblit constructor) 에서처럼 복사 및 변형되지 않습니다. 복사 생성자와 후미 생성자는 미묘하게 다릅니다.

C++의 모든 structs/class에는 복사 생성자가 있지만 (컴파일러가 선언하지 않으면 컴파일러에서 항상 생성자를 생성 함) D의 모든 구조체에는 사후 생성자가없는 것은 아닙니다. 사실, 대부분은 그렇지 않습니다. 컴파일러는 struct에 postblit 생성자가있는 다른 구조체가 들어 있으면 하나를 생성하지만 그렇지 않으면 생성하지 않을 것이고 복사는 비트 단위 복사를 수행 할 것입니다. 그리고 사후 구축물이없는 경우에는 암시 적 또는 명시 적으로 호출 할 수 없습니다. 이제

, 우리는이

struct A 
{ 
} 
pragma(msg, "A: " ~ __traits(allMembers, A).stringof); 

A: tuple() 

A을 인쇄 컴파일하는 경우는 회원이 없습니다 - 그것은 멤버 변수 또는 기능을합니다. 아무도 선언되지 않았으며 컴파일러가 아무 것도 생성하지 않았습니다.

struct B 
{ 
    A a; 
    string s; 
} 
pragma(msg, "B: " ~ __traits(allMembers, B).stringof); 

인쇄

B: tuple("a", "s") 

그것은 두 멤버가 - 명시 적으로 선언 된 멤버 변수를. 어떤 기능도 가지고 있지 않습니다. 멤버 변수를 선언하는 것이 컴파일러가 어떤 함수를 생성하는 이유는 아닙니다.그러나, 우리는

struct C 
{ 
    this(this) 
    { 
     import std.stdio; 
     writeln("C's postblit"); 
    } 

    int i; 
    string s; 
} 
pragma(msg, "C: " ~ __traits(allMembers, C).stringof); 

컴파일 할 때 그것은뿐만 아니라 두 개의 멤버 변수가 나열되어 있습니다

C: tuple("__postblit", "i", "s", "__xpostblit", "opAssign") 

을 인쇄뿐만 아니라 (명시 적으로 선언 postblit 생성자 인)뿐만 아니라 __xpostblitopAssign__postblit있다 . __xpostblit은 (a 초에서 그 자세한) 컴파일러에 의해 생성 된 postblit 생성자이며, (C가 postblit 생성자를 가지고 있기 때문에, 필요) opAssign 컴파일러가 생성 한 할당 연산자이다.

struct D 
{ 
    C[5] sa; 
} 
pragma(msg, "D: " ~ __traits(allMembers, D).stringof); 

인쇄

__xpostblit하지만 __postblit을 가지고
D: tuple("sa", "__xpostblit", "opAssign") 

참고. 그것은 명시 적으로 선언 된 사후 생성자가 없기 때문입니다. __xpostblit이 생성되어 각 멤버 변수의 사후 생성자를 호출했습니다. saC '(S)의 고정 배열하고, C는 postblit 생성자를 갖는다. 그래서 제대로 sa을 복사하기 위해, C에 대한 postblit 생성자는 sa의 각 요소에 호출해야합니다. D__xpostblit입니다. C__xpostblit을 가지고 있지만 그 __xposblit 단지의 __postblit를 호출 그래서, postblit 생성자 어떤 회원이 없습니다.

struct E 
{ 
    this(this) 
    { 
     import std.stdio; 
     writeln("E's postblit"); 
    } 

    C c; 
} 
pragma(msg, "E: " ~ __traits(allMembers, E).stringof); 

인쇄

E: tuple("__postblit", "c", "__xpostblit", "opAssign") 

그래서, E-C 등 - __postblit__xpostblit 모두 있습니다. __postblit는 명시 적 postblit 생성자이며, __xpostblit 그러나,이 경우, 구조체는 실제로 그렇게 __xpostblit__postblit 전화보다 더 관련이하는 postblit 생성자와 멤버 변수를 가지고, 컴파일러에 의해 생성 된 것입니다. 당신이 그래서

__posblit: 
C's postblit 
__xposblit: 
C's postblit 

인쇄 할

void main() 
{ 
    import std.stdio; 
    C c; 
    writeln("__posblit:"); 
    c.__postblit(); 
    writeln("__xposblit:"); 
    c.__xpostblit(); 
} 

한 경우

void main() 
{ 
    import std.stdio; 
    D d; 
    writeln("__xposblit:"); 
    d.__xpostblit(); 
} 

이 있다면 그것은

를 인쇄 할 반면

은 둘 사이에 진짜 차이가 없습니다

__xposblit: 
C's postblit 
C's postblit 
C's postblit 
C's postblit 
C's postblit 

D의 멤버 인 sa의 각 요소에 대해 C '엽서가 다섯 번 호출됩니다. 단지 암시 한 - 그것은 명시 적 postblit 생성자가 없기 때문에 우리는, D__postblit를 호출 할 수 있습니다.

void main() 
{ 
    import std.stdio; 
    E e; 
    writeln("__posblit:"); 
    e.__postblit(); 
    writeln("__xposblit:"); 
    e.__xpostblit(); 
} 

__posblit: 
E's postblit 
__xposblit: 
C's postblit 
E's postblit 

를 인쇄 할 것이다 그리고이 경우, 우리는 __postblit__xpostblit가 다른 것을 볼 수 있습니다. __postblit을 호출하면 명시 적으로 선언 된 포스트잇 생성자가 호출되는 반면 __xpostblit은 멤버 변수의 포스트 블러 생성자를 호출합니다.

그리고 물론

, AB이 posblit 생성자하고있는 멤버가없는이없는, 때문에 __postblit 또는 그들에 __xpostblit 중 하나를 호출하는 것은 불법이 될 것입니다.

그렇습니다. 예, 포스트 블릿 생성자를 명시 적으로 호출 할 수 있습니다. 단 하나만있는 경우에만 호출 할 수 있습니다. 함수가 __으로 시작하거나 오버로드 된 연산자 중 하나 (따라서 op으로 시작하는 경우)는 거의 명시 적으로 호출하면 안됩니다.이 함수에는 후미 생성자가 포함됩니다. 그러나 합법적 인 이유를 찾은 경우 __postblit이 아닌 __xpostblit을 호출하려고합니다. 그렇지 않으면 구성원 변수의 후불이 실행되지 않습니다. __traits(hasMember, S1, "__xpostblit")을 수행하거나 std.traits에서 잘못 명명 된 hasElaborateCopyConstructor을 사용하여 테스트 할 수 있습니다 (대부분의 코드는 더 관용적이므로 hasElaborateCopyConstructor을 사용해야합니다). 웬일인지 __postblit에 전화하고 싶다면 std.traits보다는 __traits으로 테스트해야합니다. 왜냐하면 druntime 외부의 아무 것도 형식이 __postblit으로 선언 되었기 때문에 걱정하지 않기 때문입니다. posblit 생성자에 대해 신경 쓰는 것은 __postblit이 선언되었는지 여부에 관계없이 __xpostblit을 대상으로합니다.

0

D는 자체 복사 생성자가없는,하지만 당신은 f.tupleof가 있습니다

foo(f.tupleof).bar() 

로 (적어도 얕은 복사본을 만드는 것) 기존의 내용으로 암시 적 생성자를 호출 할 수 함수 인자 목록으로의 자동 확장에 적합한 형태로 구조체 멤버리스트.