C++ 공부

스마트포인터와 벡터를 이용한 객체 생성 기초 (+ 이름 검색하기)

Client Side 2025. 9. 8. 14:48

예문

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class Student {
private:
    string name;
    int score;
    
public:
    Student(string n, int s) : name(n), score(s) {
        cout << "Student 객체 생성: " << name << endl;
    }
    ~Student() { 
        cout << "Student 객체 소멸: " << name << endl;
    }
    
    void printInfo() {
        cout << "이름: " << name << ", 점수: " << score << endl;
    }
};

int main() {

    vector<unique_ptr<Student>> students;
    
    students.push_back(make_unique<Student>("홍길동",100));
    students.push_back(make_unique<Student>("돌쇠",90));
        
    for (auto& student : students)
        {
            student->printInfo();
        }
        
        
        
    bool found = false;
	for (const auto& student : students)
	{
		if (player->getName() == findName)
		{
			student->printInfo();
			found = true;
			break;
		}
	}

	if (!found)
	{
		cout << "해당 이름의 학생을 찾을 수 없습니다." << endl;
	}
        
        
    return 0;
}

 

 

출력값

Student 객체 생성: 홍길동
Student 객체 생성: 돌쇠
이름: 홍길동, 점수: 100
이름: 돌쇠, 점수: 90
Student 객체 소멸: 홍길동
Student 객체 소멸: 돌쇠

 

 

사용된 개념 정리

 

1. 초기화 리스트

    Student(string n, int s) : name(n), score(s) {}

생성자 함수에서 생성자가 실행되기 전에 멤버변수를 초기화 해준다.

그냥 생성자 본문 안에서 대입하는 것보다 성능도 좋고, 코드도 깔끔해진다. 

특히 const 멤버 변수나 참조형 멤버 변수는 초기화 리스트로만 초기화 할 수 있다.

 

2. 스마트 포인터 (unique_ptr)

    vector<unique_ptr<Student>> students;
    
    students.push_back(make_unique<Student>("홍길동",100));
    students.push_back(make_unique<Student>("돌쇠",90));
  • unique_ptr<Student>  :  uniuqe_ptr<데이터타입> 으로 스마트포인터 변수를 선언하고 
  • make_unique<Student>("홍길동",100) : make_unique<데이터타입>(매개변수값) 으로 객체를 생성해서 초기화 한다.
  • 스마트 포인터는 개발자가 일일이 delete를 하지 않아도 되기 때문에, 메모리 누수 문제나 잘못된 메모리접근 문제를 줄일 수 있다.
  • #include <memory> 추가 필요.

 

 

※ 객체 생성에는 여러가지 방법이 있다.

 

1) 포인터틀 사용하지 않고, 동적할당을 하지 않으며 바로 복사해서 사용하는 경우.

Student s("홍길동",100)
s.printInfo();
  • 객체의 메모리가 크지 않으며, 함수 안에서만 간단하게 사용할 때는 이렇게 사용해도 괜찮다.
  • 객체를 stack공간에 생성한다. 함수가 끝나도 계속 존재해야 하는 객체에는 적합하지 않다.

2) 포인터를 사용하여 동적할당을 사용하는 경우.

Student* s = new Student("홍길동",100)
s->printInfo();
delete s;
  • 객체를 heap공간에 생성한다. 이 메모리는 delete 해주지 않는 이상 사라지지 않는다.
  • 프로그램 실행 중에 필요한 만큼 메모리를 할당하거나 해제할 수 있어서 유연하게 사용할 수 있다.
  • 특별한 이유가 없다면 스마트 포인터를 사용하는 게 훨씬 좋다.
// 스마트포인터 사용예시
unique_ptr<Student> s = make_unique<Student>("김지혜", 98);

 

 

3. 벡터

  • 벡터 선언 : vector <데이터타입> 벡터이름;
  • 벡터에 객체 입력 : 벡터이름.push_back(객체명(객체매개변수값));
    vector<unique_ptr<Student>> students;
    
    students.push_back(make_unique<Student>("홍길동",100));
    students.push_back(make_unique<Student>("돌쇠",90));

 

※ 자주쓰는 벡터 명령어

  • push_back() : 벡터의 맨 뒤에 괄호 안의 요소를 추가한다.
  • pop_back() : 벡터의 맨 뒤에 있는 요소를 제거할 때 사용한다.
  • size() : 벡터에 현재 몇 개의 요소가 들어있는지(크기)를 알고 싶을 때 사용한다.
  • empty() : 벡터가 비어있는지 확일할 때 사용한다. 비어있으면 true를 반환한다.
  • at() 또는 [ ] : 벡터 안에 특정 위치에 있는 요소에 접근할 때 사용한다. at()은 범위를 벗어나는 인덱스를 접근할 때 범위검사를 먼저하여 예외를 발생시켜서 더 안전하게 사용할 수 있다.
  • clear() : 벡터 안의 모든 요소를 한 번에 제거한다.
  • front() : 첫 번째 요소 접근.
  • back() : 마지막 요소 접근.
  • erase() :
    • 1) 특정 위치 하나 삭제 : v.erase(v.begin() + 인덱스)
    • 2) 범위 삭제 : v.erase(시작 반복자, 끝 반복자)

 

4. 범위 기반 for 루프 (range-based for loop)

 : students 벡터의 처음부터 끝까지 각 요소를 하나씩 순회하면서 student 변수에 참조로 연결해준다.

 

전통적인 방식

for(size_t i = 0; i < students.size(); i++) 
{
    const unique_ptr<Student>& student = students[i];
    student->printInfo();
}

 

범위 기반 for 문

for(const auto& student : students) 
{
    student->printInfo();
}

 

 

 

5. 이름을 검색하여 해당 이름의 정보 출력하기

  • bool 변수를 생성해 이름을 찾았는지 여부를 체크해준다. 이름을 못 찾을 경우 예외문을 출력한다.
  • 범위 기반 for 문을 통해 벡터를 순회하여 조건에 맞는 요소를 하나씩 비교해본다.
  • name 은 get함수를 통해 값을 가져와서 findName과 비교해준다.