const 선언할 경우 해당 함수의 this는 const가 된다.

즉, 수정 불가능한 상태가 된다. 따라서, this의 모든 멤버 변수에 접근할 수 없다.

또한, 해당 함수에서는 비 const 함수를 호출할 수 없다. 왜냐면 비 const함수에서는 멤버 변수가 수정될 수 있기 때문이다.

class AA {
public:
    AA() = default;
    ~AA() = default;

    void printData(int value) const
    {
        std::cout << this->data;
        this->data = value; // 에러 
        changeData(); // 에러
    }

    void changeData(int value) 
    {
        this->data = value;
    }

private:
    int data = 0;
};
int main()
{
    std::cout << "Hello World!\n";
}

 

 

'Language > C++' 카테고리의 다른 글

[folly] 구축 및 로그 예제  (0) 2025.10.31
[poco] 로그 예제  (0) 2025.07.22
[C++20] std::span  (0) 2025.05.25

환경: c++20, 최적화 끔(-O0), 릴리즈 빌드

테스트 1

class A
{
public:
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;  
    }
private:
    int var = 100;
};

int main()
{
    A a;
    a.foo();
    A b;
    b = a;
    b.foo();
 }

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-18h] BYREF
  A b; // [rsp+24h] [rbp-14h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  b.var = a.var;
  A::foo(&b);
  return 0;
}

void __fastcall A::A(A *this)
{
  this->var = 100;
}

void __fastcall A::foo(A *this)
{
  printf("hello %d\n", (unsigned int)this->var);
}

스택에 a, b 각 4바이트씩 할당함 (멤버변수 사이즈)

클래스의 함수는 일반적인 함수로 취급 (함수명이 A::foo)

= 연산자에서 대입이 발생

테스트 2

private 변수만 늘리고 컴파일

private:
    int var = 100;
    int var2 = 200;
    int var3 = 300;

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-48h] BYREF
  A b; // [rsp+30h] [rbp-38h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  qmemcpy(&b, &a, sizeof(b));
  A::foo(&b);
  return 0;
}

멤버 변수가 많으면 memcpy로 복사함

테스트 3

class A
{
public:
    A& operator=(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;
  
    }
private:
    int var = 100;
};

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-18h] BYREF
  A b; // [rsp+24h] [rbp-14h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  A::operator=(&b, &a);
  A::foo(&b);
  return 0;
}

A *__fastcall A::operator=(A *this, const A *a)
{
  this->var = a->var;
  return this;
}

기본 = 연산자가 내가 재정의한 operator=로 대체됨

operator=는 일반적인 함수로 취급 (함수명이 A::operator=)

테스트 4

class A
{
public:
    A& daeip(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    A& operator=(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;
  
    }
private:
    int var = 100;
};
int main()
{
    A a;
    a.foo();
    A b;
    b = a;
    b.foo();
    A c;
    c.daeip(a);
 }

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-28h] BYREF
  A b; // [rsp+24h] [rbp-24h] BYREF
  A c; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  A::daeip(&b, &a);
  A::foo(&b);
  A::A(&c);
  A::daeip(&c, &a);
  return 0;
}

daeip 함수와 operator=는 기능적으로 동일함

최적화에 의해 operator= 가 삭제되고 daeip 함수로 통일됨

테스트 5

class A
{
public:
    void daeip(const A& a)
    {
        this->var = a.var;
    }
    void operator=(const A& a)
    {
        this->var = a.var;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;
  
    }
private:
    int var = 100;
};

int main()
{
    A a;
    a.foo();
    A b;
    b = a;
    b.foo();
    A c;
    c.daeip(a);
}

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-28h] BYREF
  A b; // [rsp+24h] [rbp-24h] BYREF
  A c; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  A::daeip(&b, &a);
  A::foo(&b);
  A::A(&c);
  A::daeip(&c, &a);
  return 0;
}

b = a 처럼 단순 대입만 할 경우 operator=의 리턴값을 void로 해도 무방하다.

테스트6

class A
{
public:  
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;  
    }
private:
    int var = 100;
};

int main()
{
    A a;
    a.foo();
    A& b = a;
    b.foo();
}

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::foo(&a);
  return 0;
}

A& b를 A a로 인식함

테스트7

class A
{
public: 
    A& operator=(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;  
    }
private:
    int var = 100;
};

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::foo(&a);
  return 0;
}

재정의를 해도 참조 연산 기능이 동일하여  바이너리 결과는 같음

 

	string a = "hello man world girl";

	cout << static_cast<void*>(a.data()) << endl;
	cout << a << endl;

	string b = a;
	cout << static_cast<void*>(b.data()) << endl;
	cout << b << endl;

	string c = move(a);
	cout << a << endl;
   	cout << static_cast<void*>(a.data()) << endl;
	cout << static_cast<void*>(c.data()) << endl;
	cout << c << endl;

b = a을 하게 되면 복사가 일어난다. 즉, 객체의 생성 -> 복사 -> 파괴가 두번 발생한다.

move 의 경우, 객체의 생성 후 이동만 발생한다. a의 allocator가 c로 이동되며, 이동 후 a의 allocator에는 빈 값과 빈 버퍼가 들어간다. 

 

 

'Windows > Dev' 카테고리의 다른 글

windows + mac 동시 개발 시 주의 사항  (0) 2024.10.15
[MSVC] 클래스 고찰 & 디컴파일  (0) 2024.08.08
detours 빌드 및 적용  (0) 2024.04.11
[Visual Studio 2022] curl 빌드  (0) 2023.01.30
[VC++] string deallocate  (0) 2022.05.23

+ Recent posts