장르: 애초에 역경을 딛고 이룩하는 숭고한 사랑이란 없다. 그 역경 자체가 사랑이다.
프로그램 특징: 그 곳에서 살아남는 사랑이 어떤 모습으로 걸어오는지 기다려 보고 싶다.
-
[cpp] 복사 생성자1113분복사생성자 copy constructor생략 시 컴파일러가 자동 생성해주지만 클래스 내부에서 메모리 동적 할당 및 해제하고 이를 멤버 포인터로 관리하는 경우 직접 선언해야 한다.이를 이해하기 위해선 Pass by value의 선행 이해가 필요하다.다른 함수의 매개변수로 사용되는 경우 Call by value 로 전달된다. 호출 함수 스택에 따로 메모리를 할당해 객체의 복사된 값을 전달되는 형태인데 이를 복사 생성자라고 생각하면 된다.Myclass(const Myclass &rhs)// :m_data(rhs.m_data) { this -> m_data = rhs.m_data; cout a 를 복사의 원본으로 rhs가 a를 참조하는 형태 원본을 복사하는 형태기 때문에 멤버 m_data 두 ..
-
운영체제의 작동1101분운영체제는 시스템 자원의 효율적인 관리와 안전한 접근이다.컴퓨터의 전원을 켜거나 재부팅할 때와 같이 컴퓨터를 실행하려면 초기 프로그램을 실행해야 한다.부트스트랩(초기프로그램)펌웨어에 저장된 단순한 형태의 부트스트랩은 CPU 레지스터, 장치 컨트롤러, 메모리 내용 등 시스템의 모든 측면을 초기화한다.부트스트랩은 OS 커널을 찾아 메모리에 적재하는 방법과 해당 시스템 실행 시작 방법을 알아야 한다.커널이 RAM에 로드되면 시스템과 사용자에게 서비스를 제공할 수 있다. OS는 이벤트가 없는 경우 조용히 앉아 기다리게 되는데 이벤트는 거의 항상 인터럽트를 발생시켜 신호를 보낸다.인터럽트인터럽트는 하드웨어 인터럽트와 trap이 있다. 트랩은 예외 상황(유효하지 않은 메모리 액세스)에 대한 오류이거나 소프트웨어 생..
-
관계 데이터 모델 기본 개념과 제약 조건1023분DBMS 기본 아키텍처: ANSI/SPARC외부: 사용자 : 자신만의 뷰를 가지고 디비 이용--[ 외부/ 개념 mapping ] sql 질의어를 관계대수로 전환하는 등 질의 수준 변환논리적인 데이터 독립성: 개념 스키마 변경에도 사용자는 영향 받지 않음--개념: 사용자 공동체가 보는 개념 스키마 - 어떤 데이터가 어떤 관계, 우떤 무결성 제약 조건을 가지는 지 정의 (EMP(ENO: INT, PROJ: STR ~) ...)- 데이터 베이스 당 한 개의 개념 스키마만 존재함--[개념/ 내부 mapping] 질의를 디스크 디비 접근하기 위해 변환물리적인 데이터 독립성: 내부 변화에도 개념 스키마의 변화는 없도록--내부: 물리적으로 데이터를 어떻게 저장할 지 - 보통 성능향상을 위하면 내부 스키마 변경이 바..
-
[관계 대수] 관계 연산자1023분관계 대수 relational algebra원하는 데이터를 어떠한 연산과 연산 순서로 가져오라고 명시하는 절차적인 언어. SQL의 이론적인 기초가 되는 언어다.관계 DBMS는 SQL 질의를 DBMS 내부에서 관계대수식으로 변환한 후 최적의 질의 수행 계획을 찾는다.우리는 DB에 SQL로 어떤 데이터를 달라고 명령하게 된다. 이 명령을 DBMS는 관계대수식으로 변환해서 연산을 수행하니 관계대수식을 알면 데이터 처리 방법에 대해 이해할 수 있다.관계 데이터 모델에서 지원하는 두 가지 정형적인 언어정형적인이 무슨 뜻 일까?관계 해석 relational calculus원하는 데이터만 명시관계 대수 relational algebra필수 관계 연산자Selection σselection의 조건을 predicate(술..
-
[SQL] SELECT, INSERT, DELETE, UPDATE1023분SQL과 관계대수가 뭐가 다른가?SQL은 IBM 연구소에서 관계 DBMS(System R) 연구할 때 관계대수를 기반으로 집단 함수, 그룹화, 갱신 연산을 추가해서 개발한 언어사용자가 관계 DBMS에 원하는 데이터(what) 명령 -> 관계 DBMS에서 효율적으로 처리(how)하여 반환SQL은 비절차적, 관계대수는 절차적SQL은 원하는 것만 질의에 명시하고, 관계대수식은 소괄호 ()를 이용해 관계 연산자의 수행 순서를 명시한다.SQL은 3개 종류의 연산으로 명시할 수 있다.DDL: SCHEMA(구조나 제약조건 등)을 생성하거나 변경, 제거한다. CREATE (DOMAIN, TABLE... ), ALTER TABLE, DROP DOMAIN, TABLE, VIEW ...DML: 튜플의 검색(SELECT), ..
-
[Contiguous data structures] List1020분basicsC++ 을 사용하기에 앞서 C++을 사용한 Object Oriented Programming이 어떤 것이고 쓰면 뭐가 좋은지 살펴본다.OOP는 data 와 operation(method)를 하나로 묶어서 구조체 형태로 사용하는데 이를 ADT라고 한다. 학생 데이터 베이스에 학생 정보만 있는게 아니라 학생 정보를 관리할 동작(추가, 삭제 등)을 하나로 보는 것이다.ADT(Abstract Data Type)어떻게 해야 사용할 수 있을 지가 아니라 어떤 기능을 사용할 수 있을 지 알려주기 위한 구조Tell what the program must do, but not howInformation hidingpublic interfaces/methods만을 통해 데이터에 접근할 수 있으므로 접근 제어 가..
-
[Template] Class template1018분함수 템플릿과 클래스 템플릿템플릿을 함수에서 사용할 수 있고 클래스에서 사용할 수 있다. 둘 다 틀 로 사용하는 것인데 함수 수준에서 클래스 수준으로 확대된 것만 다르다.템플릿템플릿은 overloading에서 함수를 특정 사용 매개변수, 반환 형식에 따라 여러 번 작성해줘야 한다는 불편함을 위해 효율적인 메모리와 시간 관리를 위해 나온 개념이다.// function template template tem function(tem arg){ std::cout class SortedType {private: ItemType data[MAX_ITEMS]; int length;public: SortedType(); void insertItem(ItemType value); bool f..
-
기계 학습 개요1017분기계학습(저자 오일석)을 참고했습니다.기계학습이란기계학습이란 기계를 학습시킨다는 맥락에서 여러 정의를 가진다. 기계가 주어진 데이터에 대해 올바른 분류, 예측이 가능하게끔 학습시키는 과정이다. 기계학습이란 훈련집합을 이용해 데이터 생성 과정을 역으로 추청하는 문제다.데이터 생성 과정이란, 샘플 x가 발생할 확률과 target y(결과)를 모두 알고 있는 상황을 말한다. 우리는 보통 샘플에 대해 결과값만 알거나 샘플만 가지고 결과값이 없다. 샘플이 어떠한 과정으로 데이터를 생성하는지 알면 모델은 정확한 데이터 예측 또는 가상 데이터 생성이 가능해진다.기계학습이란 훈련집합에 없는 새로운 데이터, 테스트 집합에 대해 높은 성능을 보장하는 프로그램을 만드는 것이다. 즉, 일반화하는 작업이다. 테스트 집합에 대해..
-
[Linked List] Queue1016분QueueFisrt In First Outthe other end (the front) ㅁ ㅁ ㅁ ㅁ ㅁ one end(the rear) 방향 진짜 중요하다 무조건 왼쪽으로 ~~ !!enqueue, dequeue 모두 rear와 front를 가리키는 인덱스를 +1 해 item을 넣고 빼게 된다.이때, rear idx가 [max]인 경우 front idx 부터 할당된 어레이까지 공간이 남아도 더 이상 enqueue가 되지 않는다는 한계가 있다.Circular Queue어레이를 동그랗게 이어서 여분 공간을 사용할 수 있도록 한다.dequeue : 값을 내보내고 front = front + 1 한다. enqueue: rear = rear + 1 에 넣는다.보다시피 Empty, Full 모두 front ==..
복사생성자 copy constructor
생략 시 컴파일러가 자동 생성해주지만 클래스 내부에서 메모리 동적 할당 및 해제하고 이를 멤버 포인터로 관리하는 경우 직접 선언해야 한다.
이를 이해하기 위해선 Pass by value의 선행 이해가 필요하다.
다른 함수의 매개변수로 사용되는 경우 Call by value 로 전달된다. 호출 함수 스택에 따로 메모리를 할당해 객체의 복사된 값을 전달되는 형태인데 이를 복사 생성자라고 생각하면 된다.
Myclass(const Myclass &rhs)
// :m_data(rhs.m_data)
{
this -> m_data = rhs.m_data;
cout << "Myclass(const Myclass &)" << endl;
}
int main(){
// 기본 생성자
Myclass a;
a.Setdata(10);
// 복사 생성자
Myclass b(a);
}
a 를 복사의 원본으로 rhs가 a를 참조하는 형태 원본을 복사하는 형태기 때문에 멤버 m_data 두 개가 한꺼번에 나타난다.
이를 해결하기 위해 this -> m_data 를 표현해주거나 생성자 초기화 m_data(rhs.m_data)를 이용한다.
복사 생성자 호출
- 명시적 호출
Myclass a; - 함수 형태 호출
Myclass b(a);1. 클래스가 매개변수로 사용 2. 클래스가 반환형식으로 사용 - 반환 형식으로 사용되는 경우 '이름 없는 임시 객체' 를 생성한다. 느껴지는 대로 골치 아픈 문제다.
- 함수 형태 호출에서도 두 가지 사용 형식이 존재한다.
우리에게 더 익숙한 복사 생성자 호출 상황은 아래와 같다.
Myclass b;
b = a;
복사 생성자를 매개 변수로 사용
void TestFunc(Myclass param) {}
TestFunc param의 호출은 Myclass 인스턴스 원본 a를 두고 복사본을 생성한다. (함수 내부에서 쓸 용)
그렇게 되면 쓸데없이 클래스 객체가 두 개가 된다. 하나만 있어도 되는데 두 개로 처리한 것도 문제지만 함수 호출 자체가 성능 문제로 직결되기 때문에 수정이 필요하다. 복사 생성자를 삭제할까?
Myclass(const Myclass &rhs) = delete;
가능하지만.. 함수 호출 시 삭제된 함수를 참조하려 한다는 컴파일러의 오류 메세지를 만나게 된다.
*rhs: right hand side 의 약자로 그냥 많이 쓴단다. 뭔지 잘 모르겠다.
Call by reference
void TestFunc(Myclass ¶m){}
복사 생성자를 이용하지 않고도 원본을 argument로 전달해줄 수 있게 되었다.
사용자는 TestFunc(a); 로 더 높은 성능을 이용할 수 있다.
만약 void TestFunc(Myclass *param) 이었다면 사용자는 TestFunc(&a);를 파라미터로 주었어야 할 것이다.
동일한 성능을 나타내지만 포인터를 파라미터로 받을 시 댕글링 포인터(포인팅하는 쪽이 없어지는 경우)나 의존 관계 분석 불가로 인한 코드 최적화 실패 등의 단점이 있기 때문에 참조자&로 대체할 수 있는 포인터는 무조건 대체하는 것이 좋다.
사용자가 어떠한 값을 입력해야 하고, 그 값이 함수 내에서 변형될 수 있는 지를 알 수 있는 것은 프로그램 사용에 있어서 중요한 문제다.
void TestFunc(const Myclass ¶m){}
이었다고 치자.
사용자가 TestFunc 함수 내부에서 클래스 인스터스 param.setdata(10); 등의 명령어를 입력했을 때의 결과를 알 수 있을까?
사용자는 모른다.
const 참조라 원형값을 변경할 수 없음에도 뻘짓을 하고 있을지도 모른다.
근데 원형을 파라미터로 받는 경우에는 const를 꼭 사용하자. 잠깐 편하자고 ~~ 코드 뜯어볼 일을 만들지 말자.
그래서 이제 우리가 할 것은 무엇이냐면~
동적 생성한 인스턴스의 값을 관리하는 방법에 대해 알아볼 것이다.
깊은 복사와 얕은 복사
얕은 복사: 메모리 주소 가져오기
깊은 복사: 메모리 주소의 값 가져오기
int *ptr = new int;
*ptr = 10;
int *ptr2 = new int;
ptr2 = ptr;
// 지금 ptr2 는 ptr이 값으로 가진 new int (10)의 주소를 받았다.
delete ptr;
delete ptr2;
무슨 문제가 일어날까? ptr2는 이미 delete ptr에서 자신이 가리키고 있는 메모리 주소의 집주인이 사라졌으므로 할당 해제된 상태다.
여기서 한 번 더 할당 해제를 시도하면 오류가 난다.
ptr -> 10
ptr2 ---^ [new int] (접근 불가)
*ptr2 = *ptr;
로 수정하면 ptr2 는 자신이 동적 할당한 int 메모리에 10을 넣어서 그걸 가리키고 있을 것이다.
ptr -> 10
ptr2 -> 10
포인터가 존재할 때 얕은 복사가 문제되는 상황
class Myclass
{
public:
Myclass(int nParam)
{
m_dataPtr = new int;
*m_dataPtr = nParam;
}
int getdata(){
if (m_dataptr != nullptr){
return *m_dataptr;
}
return 0;
}
private:
int *m_dataptr = nullptr;
};
int main(){
Myclass a;
Myclass b(a);
cout << a.getdata() << endl;
cout << b.getdata() << endl;
return 0;
}
문제는 어디서 나타난걸까
Myclass b(a); 를 수행하면 깊은 복사 수행이 아니기 때문에 컴파일러가 자동으로 Myclass b(a);에서
Myclass(const Myclass &rhs){
m_dataptr = rhs.m_dataptr;
}
를 실행한다.
여기서 메모리 해제를 시도했다면
// 객체 소멸 시점에 동적 할당 메모리 삭제
~Myclass() { delete m_dataptr; }
( 소멸자는 블록 {} 이 끝나면 실행된다 )
복사 생성자인 b는 원본 데이터의 m_dataptr;이 삭제된 상태에서 또 소멸자를 부르기 때문에 앞서서 봤던 해제된 메모리를 다시 해제하려고 시도한 오류가 나타난다.
그럼 또 어떡하라공
복사 생성자 정의하고 깊은 복사
Myclass(const Mydata &rhs)
{
// 디버그용
cout << "복사생성자 호출" << endl;
// 메모리 할당
m_dataptr = new int;
*m_dataptr = *rhs.m_dataptr;
}
인스턴스 복사 후 소멸자가 나와도 복사 생성자는 자신이 할당한 메모리를 가리키고 있기 때문에 더 이상 해제된 메모리를 해제하는 오류는 나타나지 않는다.
저자 왈, 이 부분 객체지향 배우면 시험 범위라니까 모두들 열심히 이해해봅시다.
추가로 ...
앞서서, 우리에게 익숙한 방식 b = a; 로 단순 대입(pass by value)한 결과에는 대입 연산자 동작 방식을 새로 정의해주어야 한다.
Myclass& operator = (const Myclass &rhs)
{
*m_dataptr = *rhs.m_dataptr;
// 객체 자신에 대한 참조 반환
return *this;
}
// b = a; 대신 아래와 같이 이용할 수도 있다.
b.operator=(b);
연산자 = 의 작동 방식을 정의해준 코드로 .. 어렵다
a의 모든 값을 새로 정의한 복사 생성자 new로 넣기 위해 깊은 복사를 정의해준건가?
b = a; 면 a의 m_dataptr 값이 = 에서 *m_dataptr = *rhs.m_dataptr;로 복사되어 b의 m_dataptr이 된건가
그럼 *rhs.m_dataptr; 를 반환하면 안되나?
... 어물쩡 넘기기 ㅎ
전체 코드
class Myclass
{
public:
Myclass(int nParam)
{
m_dataptr = new int;
*m_dataptr = nParam;
}
Myclass(const Myclass &rhs)
{
cout << "Myclass const &rhs" << endl;
m_dataptr = new int;
*m_dataptr = *rhs.m_dataptr;
}
~Myclass()
{
delete m_dataptr;
}
Myclass& operator=(const Myclass &rhs)
{
*m_dataptr = *rhs.m_dataptr;
return *this;
}
int getdata()
{
if (m_dataptr != nullptr)
return *m_dataptr;
return 0;
}
private:
int *m_dataptr = nullptr;
};
int main()
{
Myclass a(10);
Myclass b(20);
a = b;
cout << a.getdata() << endl;
return 0;
}
답은?
20
- 이 글은 최호성 저자의 이것이 C++이다 를 참고하여 작성되었습니다.
'Computer Science > Object Oriented Programming' 카테고리의 다른 글
[JAVA] 참조형 : 배열 초기화, 복사 (1) | 2025.04.16 |
---|---|
[JAVA] 이것이 자바다(3판) 5장 9번 답안 (1) | 2025.04.15 |
[Template] Class template (0) | 2024.10.18 |
[Class] Method (3) | 2024.10.16 |
[cpp] Class (1) | 2024.10.16 |