728x90

https://boycoding.tistory.com/250

C++ 09.10 - this 포인터

this 포인터 객체 지향 프로그래밍에서 가장 많은 질문 중 하나는 "클래스의 멤버 함수를 호출할 때 C++는 어떻게 호출할 객체(인스턴스)를 찾는가?" 이다. 이 질문에 대한 정답은 this라는 숨겨진

boycoding.tistory.com

 
모든 멤버 함수는 함수가 호출된 객체(인스턴스)를 가리키는 this 포인터를 가지고 있다.
호출된 객체의 주소를 가리키는 상수 포인터다.
상수 포인터 자료형이므로 포인터 자체가 다른 것을 가리키도록 할 수는 없다.
모든 과정은 컴파일러에 의해 자동으로 수행된다.
 
그러나, 명시적으로 this를 참조해야 하는 경우가 있다.
 
- 첫째, 멤버 변수와 이름이 같은 매개 변수를 가진 생성자(또는 멤버 함수)가 있는 경우, this를 사용해서 구분할 수 있다. 

class Something
{
private:
    int data;

public:
    Something(int data)
    {
        this->data = data;
        // this->data는 멤버 변수이고,
        // data는 매개 변수
    }
};

 
- 둘째, 클래스 멤버 함수가 작업 중이던 객체(인스턴스)를 반환하는 방식이 유용할 때가 종종있다. 이렇게 하면 같은 객체의 여러 멤버 함수를 연속해서 호출할 수 있는 방법이다.
만약 각각의 멤버 함수가 *this 반환한다면 체이닝 기능이 있는 새로운 버전의 Calc 만들 있다.

class Calc
{
private:
    int m_Value = 0;

public:
    Calc& Add(int value) { m_Value += value; return *this; }
    Calc& Sub(int value) { m_Value -= value; return *this; }
    Calc& Mul(int value) { m_Value *= value; return *this; }

    int GetValue() { return m_Value; }
}

int main()
{
    Calc calc;

    calc.Add(5).Sub(3).Mul(4); //함수 체이닝

    cout << calc.GetValue() << endl; // 8
    return 0;
}

출처: https://boycoding.tistory.com/250 [소년코딩:티스토리]

728x90
728x90

macOS에서 memory leak 체크하려다
-valgrind는 너무 유용하고 간단한 툴이지만: 리눅스 환경에서만 실행된다는 소식...
-sanitizer는 과제 환경인 g++ 컴파일러가 아닌 clang 컴파일러에서만 실행된다는 소식...


그렇게 알게된 게 'leaks'
macOS에서 valgrind의 역할을 해주는 요긴한 친구다 ❤️
하지만 leaks를 실행하기 위한 코드를 컴파일코드의 '어디'에 넣어야 할지 몰랐고, 이를 이해하면 과제에서 주어진 makefile의 문법을 알아야 했다. 역시 프로그래밍은 성급히 하면 오히려 꼬이고 세 배의 시간이 소요된다는 것.. ㅎㅎ 처음부터 찬찬히 해보니 성공했다!


 

1. makefile 친숙해지기 (아래링크에서 완벽 정리)
https://hwan-shell.tistory.com/188

c++] make, makefile의 사용방법(기본적인 설명)

1. makefile 이란?? 요 세개의 파일이 있다고 가정해 봅시다. 우리는 아래와 같은 명령어를 통해 실행파일을 만들어낼 수 있습니다. $ g++ -c test1.cpp add.cpp -> test1.o, add.o 파일 생성(오브젝트 파일) $ g++

hwan-shell.tistory.com

나의 makefile

CC = g++-11 --std=c++17
RD = rm -f
DoublyLinkedList.o: DoublyLinkedList.h DoublyLinkedList.cpp
	$(CC) -c DoublyLinkedList.cpp

part1_main.o: part1_main.cpp DoublyLinkedList.h
	$(CC) -c part1_main.cpp

part1_main.out: DoublyLinkedList.o part1_main.o
	$(CC) DoublyLinkedList.o part1_main.o -o part1_main.out

part2_main.o: part2_main.cpp DoublyLinkedList.h
	$(CC) -c part2_main.cpp

part2_main.out: DoublyLinkedList.o part2_main.o
	$(CC) DoublyLinkedList.o part2_main.o -o part2_main.out

clean:
	$(RD) *.o

→ 근데 결론은,, Makefile을 수정하지 않아도 됐더라는 것..! ㅋㅋ
그래두 이제 Makefile 읽을 수 있음
 
1. 일단 첫 번째는 DoublyLinkedList.o를 만들기 위한 코드임.
2. 두 번째는 part1_main.o를 만들기 위한 코드임. 앞에 Make 쳐주면 됨.
 
하지만, 내가 실제로 커맨드로 입력하는 코드는 $make part1_main.out (과제 명세) 임.

3. '$make part1_main.out'는 part1_main.out를 만드는 makefile 문법이 반영된 커맨드임. 이걸 터미널에 입력하면, makefile의 세 번째 코드가 실행됨. 세 번째 코드의 오른쪽 부분을 살피면, "part1_main.out를 만들기 위해서는 DoublyLinkedList.o와 part1_main.o가 필요하다"는 것을 알 수 있음. 이를 위해, 아까 언급한 첫 번째 두 번째 코드가 실행되는 것임.

$(CC) DoublyLinkedList.o part1_main.o -o part1_main.out

- $(CC)에는 g++-11 --std=c++17가 입력됨.

- 첫 번째 두 번째 코드를 통해 생성된 DoublyLinkedList.o와 part1_main.o를 활용하여

- part1_main.out라는 이름의 executable file을 만들어라

 

2. brew install leaks

사랑스러운 leaks를 mac에 설치하는 커맨드임

 

3. 아래 영상을 따라함

https://www.youtube.com/watch?v=bhhDRm926qA

이 영상이 진짜 최고임...
 
+추가 →근데 이거 볼 것도 없음. 위 영상에서 다 설명해줌.
https://stackoverflow.com/questions/59122213/how-to-use-leaks-command-line-tool-to-find-memory-leaks

How to use leaks command-line tool to find memory leaks?

leaks command-line tool will report the address of the leaked memory the size of the leak (in bytes) the contents of the leaked buffer like the following: Process: checker [84357] Path: ...

stackoverflow.com

커맨드라인에 이하를 입력

export MallocStackLogging=1 

→ memory leak과 관련된 모든 log를 터미널창에 출력해주도록 설정하는 것(option)

 
make part1_main.out

executable file 생성

 
leaks --atExit -- ./part1_main.out

현재 디렉토리의 part1_main.out를 실행하는데, memory leaks을 detect하고 그 결과를 보고하라!
 

  • leaks -atExit : tells which leaks exist, but not where any leaked allocation came from
  • MallocStackLogging : creates logs that can tell me where the leaked allocations came from, but the logs are automatically deleted when the program exits, and leaks -atExit runs, obviously, at exit

실행 결과

2 7
1 1
R
L
P 2
L
L
P 3
V
1 2 1 3 
part2_main.out(10555) MallocStackLogging: stack logs deleted from /tmp/stack-logs.10555.1008e8000.part2_main.out.0iRX5O.index
Process 10555 is not debuggable. Due to security restrictions, leaks can only show or save contents of readonly memory of restricted processes.

Process:         part2_main.out [10555]
Path:            /Users/USER/*/part2_main.out
Load Address:    0x10082c000
Identifier:      part2_main.out
Version:         0
Code Type:       ARM64
Platform:        macOS
Parent Process:  leaks [10554]

Date/Time:       2023-10-23 14:19:02.367 +0900
Launch Time:     2023-10-23 14:18:53.129 +0900
OS Version:      macOS 13.1 (22C65)
Report Version:  7
Analysis Tool:   /usr/bin/leaks

Physical footprint:         3585K
Physical footprint (peak):  7601K
Idle exit: untracked
----

leaks Report Version: 4.0, multi-line stacks
Process 10555: 228 nodes malloced for 117 KB
Process 10555: 0 leaks for 0 total leaked bytes.

leaks(10554) MallocStackLogging: stack logs deleted from /tmp/stack-logs.10554.104b18000.leaks.MUDEON.index

0 leaks for 0 total leaked bytes. !!!!

나의 소중한 코드에세서는 다행히 leak이 detect되지 않음...🥰🥰🥰

728x90

728x90

C++에서 cin을 사용하여 입력을 받을 때, 기본적으로 공백 문자(스페이스, 탭, 개행)을 기준으로 데이터를 분리

→ 띄어쓰기(스페이스)는 cin에서 입력을 구분하는 구분자로 작용함

 

예시

#include <iostream>
using namespace std;

int main() {
    int a, b, c;
    cout << "정수 a, b, c를 입력하세요: ";
    cin >> a >> b >> c;

    cout << "입력된 값: a=" << a << ", b=" << b << ", c=" << c << endl;
    
    return 0;
}

 

"1 2 3"로 입력하면 cin은 이를 공백 문자를 기준으로 각 변수에 할당함


사례

#include <iostream>
using namespace std;

int main() {

    int N, M;
    cin >> N >> M;
    cout << "N: "<< N <<", M: " << M << endl;

    char a;
    cin>>a;
    if (a=='*'){
        int b;
        cin>>b;
        cout<<b<<endl;
    }

    return 0;
}

Output

728x90
728x90

배열 사이즈를 미리 알 수 없을 때

new operator를 통해 컴파일이 아닌 프로그램 실행 중 동적으로 할당할 수 있다
위 예시와 같이 미리 int로 size 변수를 선언한 후 → new int[size] 선언 → cin 입력으로 저장하면 된다

int main() {

    int size, i;
    std::cout << "배열의 크기를 입력하세요: ";
    std::cin >> size;
    int* dynamicArray = new int[size]; 
    //배열 사이즈를 미리 알 수 없을 때, new operator를 통해 컴파일이 아닌 프로그램 실행 중 동적으로 할당할 수 있다
	//위 예시와 같이 미리 int로 size 변수를 선언한 후 → new int[size] 선언 → cin 입력으로 저장하면 된다
    for (i=0;i<size;i++){
        dynamicArray[i] = i;
    }

    for (i=0;i<size;i++){
        cout<<dynamicArray[i]<<endl;
    }
    
    delete[] dynamicArray;

}

/*
배열의 크기를 입력하세요: 5
0
1
2
3
4
*/

- new 연산자를 사용한다면 memory leak를 방지하기 위해 반드시 delete를 해주어야 한다

 

동적 할당의 유용성

 

가변적인 크기: 프로그램이 실행 중, 데이터 구조의 크기를 변경해야 할 때 유용함

- 배열의 크기를 동적으로 조정하거나 필요에 따라 메모리를 할당할 수 있음

 

메모리 사용 최적화: 정적 할당(static allocation)은 메모리를 미리 할당하므로 메모리 낭비가 발생할 수 있음

- 동적 할당은 필요한 만큼 메모리를 할당하므로 메모리 사용을 최적화할 수 있음

 

유연성: 동적 할당은 복잡한 데이터 구조를 생성하고 관리하는 필요한 '유연성'을 제공

- 동적으로 할당된 메모리를 사용하여 복사, 이동, 삽입, 삭제 등의 작업을 수행할 있음

 


delete의 추가 예시

MyClass* obj = new MyClass;
delete obj; // 클래스 객체 해제
int* dynamicArray = new int[10];
delete[] dynamicArray; // 배열 해제
class MyClass {
private:
    int* data;
public:
    MyClass() {
        data = new int;
    }
    ~MyClass() {
        delete data; // 멤버 변수에 대한 동적 할당 메모리 해제
    }
};
class MyClass {
private:
    int* dataArray;
public:
    MyClass(int size) {
        dataArray = new int[size];
    }
    ~MyClass() {
        delete[] dataArray; // 배열에 대한 동적 할당 메모리 해제
    }
};

 

728x90

'개발 > c++' 카테고리의 다른 글

[디버깅 노트] 포인터 관련 유의사항  (0) 2023.10.20
[c++] 입력에서 띄어쓰기  (1) 2023.10.20
[c++] vector  (0) 2023.09.25
[c++] const / 초기화 리스트!!  (0) 2023.09.24
[c++] 서로 다른 & (참조자/주소반환)  (0) 2023.09.24

728x90

const 개념 정리

원문 출처

https://easycoding91.tistory.com/entry/C-%EA%B0%95%EC%A2%8C-const-%EC%9C%84%EC%B9%98%EC%9D%98-%EC%9D%98%EB%AF%B8%EC%99%80-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95

 

 

[C++ 강좌] const 위치의 의미와 사용 방법

const는 constant의 약자로 명사형 사전적 의미로 "상수"를 뜻합니다. 따라서 말 그대로 C++에서 const는 그 대상을 변경하지 않는 "상수"를 의미합니다. 의미하는 바는 굉장히 쉽지만 const 위치에 따라

easycoding91.tistory.com


*멤버 → '클래스'와 관련된 개념

- 멤버 변수: 클래스 내부에 선언된 변수

클래스의 객체(인스턴스)가 가지는 속성(attribute), object의 상태를 저장하고 나타내며, 클래스의 모든 인스턴스가 공유

 

- 멤버 함수: 클래스 내부에 정의된 함수

object가 수행하는 동작(behavior) 나타냄, 멤버 함수는 객체의 상태를 조작하거나 해당 객체와 관련된 작업을 수행

 

Const (4types)

1. const 변수

1-1) const '비'멤버 변수 (클래스 밖)

const int num = 1; // 일반적인 표현
int const num = 1; // 위와 같은 의미
 
num = 2;           // Compile Error

 

1-2) const 멤버 변수 (클래스 안)

class Foo
{
	const int num; // 메모리 할당이 아님
	Foo(void)
		: num(1) // const int num = 1;
	{
	}
};
 
class Bar
{
	const int num;
	Bar(void)
	{
		num = 1; // Compile Error
		// const int num;
		// num = 1;
	}
};

const 변수는 반드시 선언 시 초기화를 해야 함

class의 멤버 변수를 const로 선언 시에는 반드시 초기화 리스트(Initialize List)를 사용해야 함

 

*C++11부터는 class 내부에서 const int num = 1;과 같이 선언 및 초기화가 가능하기도 하지만, 초기화 리스트를 사용하여 멤버 변수를 초기화하는 것이 일반적임

*class 내부에서 const int num;을 한 것은 메모리를 할당하는 것이 아니라 단순히 컴파일러에게 class가 어떤 형태인지 알린 것일 뿐

*따라서 class 내부에서는 const int num;과 같은 형태가 가능 => 이후 초기화 리스트로 실제 값 초기화

 

1-3) const 포인터 변수

a) const 위치가 맨 앞에 있으면서, 포인터 변수가 가리키는 값에 대하여 상수화

int num = 1;
const int* ptr = &num; // *ptr을 상수화
 
*ptr = 2; // Compile Error
num = 2;  // Pass

**포인터를 통해 num의 value를 조작하는 것을 불가능하게 만든 것 (*ptr = 2는 컴파일에러)

**num 자체가 상수화된 것이 아님 (num=2;와 같은 수정 가능)

 

b) 포인터 변수 자체를 상수화

int num1 = 1;
int num2 = 2;
int* const ptr = &num1; // ptr을 상수화
 
ptr = &num2; // Compile Error

 

2. const 멤버 함수

비 멤버 함수를 상수화시킬 수는 없음

반드시 class 내부에서 정의된 멤버함수만 가능 !! → 실제 상수화되는 대상은 해당 class의 멤버 변수

의미: 해당 멤버 함수 내에서는 동일한 class의 모든 멤버 변수를 상수화시킨다 (멤버 함수의 local variable은 조작 가능, 상수화되지 않음)

int GetString(void) const; // Compile Error
 
class Foo
{
	int num = 1;
 
	int GetNum(void) const
	{
		int a = 1;
		a++;   // 지역 변수는 가능
 
		num++; // Compile Error
		return num;
	}
};

 


 

초기화 리스트 개념 정리

https://velog.io/@sjongyuuu/C-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%B4%88%EA%B8%B0%ED%99%94%EB%A6%AC%EC%8A%A4%ED%8A%B8

 

C++ 생성자(Constructor)와 초기화 리스트(Initialization List)

이번 포스팅은 C++ 생성자와 초기화 리스트에 대해 다루어 보려고 한다.

velog.io

 

728x90
728x90

순서로 둘을 구분!


int *ptr = &num;

- 변수 num의 주소값을 반환해서, 포인터 ptr에 저장하라

- ptr == &num

- *ptr = num

int &num2 = num1;

- 이미 선언된 변수 num1에 대한 참조자를 num2로 선언하겠다

- num1: 이미 선언된 원본 변수

- num2: num1의 참조자

- num2과 num1은 같은 value를 다루며, num2를 통해 num1에 직접 조작을 가할 수 있다 (간접참조 x)

 

**참조자는 변수를 대상으로만 선언이 가능함

728x90

'개발 > c++' 카테고리의 다른 글

[c++] vector  (0) 2023.09.25
[c++] const / 초기화 리스트!!  (0) 2023.09.24
[c++] 동적 결합  (0) 2023.09.11
[c++] virtual 통한 가상 메서드 선언, public 함수 다형 상속  (0) 2023.09.10
[c++] 클래스 상속  (0) 2023.09.10

+ Recent posts