Info

알던 내용이긴 한데, 헷갈려서 정리하는겸 생성자가 호출되는 시기와 operator가 호출되는 시기에 대한 글을 써보려한다.

바로 예제를 먼저 확인해보자.

#include <cstdio>
 
template<unsigned N>
struct StaticString {
    // ctor from C‑string
    StaticString(const char* s) {
        printf("→ StaticString(const char*) ctor\n");
        // … copy into _data …
    }
    // default ctor
    StaticString() {
        printf("→ StaticString() default ctor\n");
    }
    // copy ctor
    StaticString(const StaticString& o) {
        printf("→ StaticString(const StaticString&) copy ctor\n");
    }
    // assignment from C‑string
    StaticString& operator=(const char* s) {
        printf("→ operator=(const char*)\n");
        return *this;
    }
    // copy‑assignment
    StaticString& operator=(const StaticString& o) {
        printf("→ operator=(const StaticString&)\n");
        return *this;
    }
};
 
int main() {
    puts("1) StaticString<8> a = \"abc\";");
    StaticString<8> a = "abc";
    // Output: → StaticString(const char*) ctor
 
    puts("\n2) StaticString<8> b; b = \"xyz\";");
    StaticString<8> b;
    b = "xyz";
    // Output:
    // → StaticString() default ctor
    // → operator=(const char*)
 
    puts("\n3) StaticString<8> c = a;");
    StaticString<8> c = a;
    // Output: → StaticString(const StaticString&) copy ctor
 
    puts("\n4) StaticString<8> d; d = a;");
    StaticString<8> d;
    d = a;
    // Output:
    // → StaticString() default ctor
    // → operator=(const StaticString&)
 
    return 0;
}

예시로 구분할 수 있듯이, 생성과 동시에 할당을 진행하는 경우에는 생성자로 취급되며, 이후의 사용되는 operator의 경우에는 그것에 맞는 호출을 가지게 된다.


내가 헷갈린 부분에 대해서 짚어보겠다.

예시의 4번 연산과 같이 진행될 경우 operator=StaticString(…)가 연속적으로 호출되어 비효율적으로 동작하는게 아닐까 했는데.

operator=에서 참조를 반환하는 이유는 연속 호출(method chaining)을 구현하기 위한이지 반환하여 재할당하는 의도가 아니라는 것을 망각했다.


4번에서 d = a의 호출은 d.operator=(a)와 같다는 것을 기억하자.