Post

[ STUDY/Effective C++ ] 2022. 8. 17. 23:06

 

class Transaction {
public:
	Transaction();
	virtual void logTransaction() const = 0;
	...
};

Transaction::Transaction() //기본 클래스 생성자
{
	...
	logTransaction();
}

class BuyTransaction: public Transaction { //Transaction의 파생 클래스
public:
	virtual void logTransaction() const;
	...
};
BuyTransaction b;

위와 같은 코드가 있을때 BuyTransaction b; 코드를 작성한다면 호출되는 logTransaction함수는 BuyTransaction의 것이 아니라 Transaction의 것이다.

 

기본클래스의 생성자가 호출 될 동안에는, 가상 함수는 절대로 파생 클래스 쪽으로 내려가지않는다.

( = 기본 클래스 생성과정에서는 가상함수가 먹히지않는다.)

 

왜냐하면 기본 클래스 생성자는 파생 클래스 생성자보다 앞서 실행되기때문에, 기본 클래스 생성자가 돌아가고 있을 시점에는 파생 클래스 데이터 멤버는 아직 초기화된 상태가 아니다.

 

파생클래스(BuyTransaction)만의 데이터가 아직 초기화된 상태가 아니기때문에 아예 없는것으로 취급하는게 안전하다고 생각하기때문에 파생클래스의 객체는 기본 클래스 부분이 생성되는 동안은, 기본 클래스타입의 객체로 취급한다.

 

그리고 C++은 초기화되지 않은 영역을 건드리는 것 자체를 못하도록 막기때문에 가상함수가 파생클래스 쪽으로 내려가지않는다.

 

소멸자 또한 마찬가지로 소멸자가 호출되고나면, C++은 파생 클래스만의 데이터 멤버를 없는것처럼 취급하고 진행한다.

 

 

 

 

이러한 문제점을 해결하기위해서는 어떻게해야할까?

class Transaction {
public:
	explict Transaction(const std::string& logInfo);
	void logTransaction(const std::string& logInfo) const; //비가상 함수
	...
};

Transaction::Transaction(const std::string& logInfo)
{
	...
	logTransaction(logInfo); //비가상 함수 호출
}

class BuyTransaction: public Transaction {
public:
	BuyTransaction(parameters)
	 : Transaction(createLogString (parameters) ) //로그 정보를 기본 클래스 생성자로 넘김
	 {...}
	 ...
     
private:
	static std::string createLogString(parameters);
};

바로 가상함수를 비가상 멤버함수로 바꾸는것이다. 

위의 코드들을 예시로 들자면,

파생클래스의 생성자들이 필요한 로그 정보를 Transaction의 생성자로 넘기면=>

비가상 함수로 바꾼 logTransaction이 안전하게 수행된다. (정적 멤버로도 되어있기때문에 더욱더 안전)

 

필요한 초기화 정보를 파생클래스에서 기본 클래스 생성자로 올려준다는 얘기니

기존에 기본 클래스에서 정의한 가상함수를 파생클래스에서 사용할려고한 의도와 똑같이 사용이 가능하다.

Post

[ STUDY/언리얼 ] 2022. 8. 17. 20:03

 

 

튜토리얼 강의를 듣는도중 선생님 혼자서 저도 모르는 플레이어 스타트 위치를 지정하고계셨습니다.

 

오른쪽 상단에 빨간박스친구.. 전 없는데용..?

그리고 플레이버튼을 누르면 항상 카메라가 위치해있는 곳에서 플레이어가 짠 나타나 시작하기때문에 뭔가 이상함을 느껴 따로 찾아보았습니다.

 

상단창에서 '창' ->'액터배치'를 눌러주시고

 

'플레이어 스타트'를 꾹 누른상태로 화면으로 끌어당겨 원하는 위치에 배치시키면됩니다.

 

나도 강의영상처럼 플레이어스타트 생겼다!o(〃^▽^〃)o

그럼 플레이버튼을 눌렀을때 그 위치로 플레이어가 나타나 시작을 하게됩니다 :D 

 

 

+) 플레이어 스타트 액터가 위치한 곳이 아닌 다른곳에서 플레이하고싶을때는?

에디터 뷰포트(게임화면)내에서 원하는 위치에 마우스 우클릭하시고 '여기에서 플레이' 누르시면 됩니다 :D

'STUDY > 언리얼' 카테고리의 다른 글

[Unreal] Yaw, Pitch, Roll 이해하기 쉽게 알아보기  (0) 2022.08.28

Post

[ STUDY/Effective C++ ] 2022. 8. 17. 19:44

c++은 예외를 내보내는 소멸자를 좋아하지않는다.

당연하다. 소멸자가 그냥 조용히 소멸하는것이 아닌 예외까지 발생하면 프로그램의 불완전 종료 나 미정의 동작의 위험을 내포하고있기때문이다.

 

하지만 항사 우리가 원하는대로 코드를 짤 순 없다.

만약에 예외를 던지고 실패할 수 있는 코드를 소멸자에 넣어한다면 어떻게 해야할까

 

1. 프로그램 바로 끝내기

DBConn::~DBConn()
{
	try {db.close(); }
    catch (...) {
    	close 호출이 실패했다는 로그 출력;
        std::abort();
	}
}

abort를 호출해서 못 볼꼴을 미리 안보여준다.

 

 

2. 예외 삼켜버리기(무시하기)

DBConn::~DBConn()
{
	try {db.close(); }
    catch (...) {
    	close 호출이 실패했다는 로그 출력;
	}
}

발생한 예외를 그냥 무시하더라도 프로그램이 신뢰성 있게 지속될 경우에만 사용하자.

 

 

3. 사용자가 직접처리하기

void close()
{
	db.close();
    closed = true;
}

DBConn::~DBConn()
{
	if(!closed)
	try {db.close(); }
    catch (...) {
    	close 호출이 실패했다는 로그 출력;
        ...//실행끝내거나 예외무시
	}
}

사용자함수를 만들어 DBConnection이 닫혔는지 여부를 유지가능하며 사용자가 에러를 처리할 수 있는 기회를 가질 수 있다. 닫히지않았다면 DBConn의 소멸자에서 닫을 수도 있다. 

 

이렇게하면 데이터베이스 연결이 누출되지않으나, 소멸자에서 호출하는 close마저 실패한다면 다시 위의 1,2번 처럼 돌아올 수 밖에 없긴하다.

 

 

 

Post

[ STUDY/코딩문제 ] 2022. 8. 14. 23:34

행성 연결 성공


 

시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율
1 초 256 MB 3807 1734 1236 42.591%

문제

홍익 제국의 중심은 행성 T이다. 제국의 황제 윤석이는 행성 T에서 제국을 효과적으로 통치하기 위해서, N개의 행성 간에 플로우를 설치하려고 한다.

두 행성 간에 플로우를 설치하면 제국의 함선과 무역선들은 한 행성에서 다른 행성으로 무시할 수 있을 만큼 짧은 시간만에 이동할 수 있다. 하지만, 치안을 유지하기 위해서 플로우 내에 제국군을 주둔시켜야 한다.

모든 행성 간에 플로우를 설치하고 플로우 내에 제국군을 주둔하면, 제국의 제정이 악화되기 때문에 황제 윤석이는 제국의 모든 행성을 연결하면서 플로우 관리 비용을 최소한으로 하려 한다.

N개의 행성은 정수 1,…,N으로 표시하고, 행성 i와 행성 j사이의 플로우 관리비용은 Cij이며, i = j인 경우 항상 0이다.

제국의 참모인 당신은 제국의 황제 윤석이를 도와 제국 내 모든 행성을 연결하고, 그 유지비용을 최소화하자. 이때 플로우의 설치비용은 무시하기로 한다.

입력

입력으로 첫 줄에 행성의 수 N (1 ≤ N ≤ 1000)이 주어진다.

두 번째 줄부터 N+1줄까지 각 행성간의 플로우 관리 비용이 N x N 행렬 (Cij), (1 ≤ i, j ≤ N, 1 ≤ Cij ≤ 100,000,000, Cij = Cji, Cii = 0) 로 주어진다.

출력

 

모든 행성을 연결했을 때, 최소 플로우의 관리비용을 출력한다.

 


풀이

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

int V, E;
vector<pair<long long, pair<int, int>>> edge;
int parents[1000];
int edgenum = 0;

int FindRoot(int x)
{
	if (x == parents[x])
		return x;
	return parents[x] = FindRoot(parents[x]);
}

void Merge(int x, int y)
{
	x = FindRoot(x);
	y = FindRoot(y);

	if (x == y)
		return;
	if (y > x)
		parents[y] = x;
	else
		parents[x] = y;
}





int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);


	for (int i = 0; i < 1000; i++)
	{
		parents[i] = i;
	}

	int N;
	long long res = 0;
	cin >> N;

	long long input;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++) {
			cin >> input;
			if ((i < j) && (i != j)) {
				edge.push_back({ input,{i,j} });
			}
		}

	}


	sort(edge.begin(), edge.end());

	for (int i = 0; i < edge.size(); i++)
	{
		if (FindRoot(edge[i].second.first) == FindRoot(edge[i].second.second))
			continue;

		Merge(edge[i].second.first, edge[i].second.second);
		res += edge[i].first; 
		edgenum++;

		if (edgenum == N - 1)
			break;

	}
	cout << res<<'\n';
}

이 문제는 같은종류의 문제였던 최소스패닝트리의 전력난과 최소스패닝트리의 문제풀이만을 생각하고있다가 통수맞았습니다! 사실 통수가 아니라 제 지식과 응용의 문제이기도 하겠지만 이전까지 pair<int,pair<int,int>>를 잘 해오다가 이번 문제에서는 똑같이하면 안된다는것을 알았습니다.

Vector<pair<long long,pair<int,int>>>했을때 (좌) , pair<long long,pair<int,int>> 했을때(우)

위 사진은 각각 다르게 자료형을 가졌을때, sort하고 난 다음의 모습입니다.

vector<pair<long long,pair<int,int>>>로 하였을때는 sort가 cost의 오름차순으로 잘 정렬되어있지만, pair<long long,pair<int,int>> 를 했을 경우에는 중간부터 정렬이 어긋난것을 알 수가 있습니다.

 

이 원인은 알고보니 sort함수때문에 일어났는데요..제가 바보같이 pair<long long,pair<int,int>>를 했을 당시 sort를 (edge, edge+N)으로 두는 어마어마한 실수를 하였습니다. 분명 마지막 항목은 N이 아니고 그 배일텐데.. 제가  정말 앞에 푼 문제들만 생각하고 심각한 오류를 범했죠..

 

다행히 Vector<pair<long long,pair<int,int>>>를 했을때는 sort를 sort(edge.bigin(), edge.end())로 두었기에 제가 신경쓰지 않더라도 알아서 잘 정렬을 해주었습니다.

 

이 글을 쓰면서 다시 한번 쭉 검토해보니 통수가 아니라 정말 바보같은 실수네요! 오랜만에 문제를 풀어보았더니 이런 실수나 하고..부끄럽습니다! 열심히 이제부터 다시 공부해야겠네요 :D

 

끝만 잘 생각한다면 그냥 크루스칼 알고리즘 그대로 써도 될 정도의 최소스패닝트리 기본문제였습니다.

 

 

 

https://www.acmicpc.net/problem/16398

 

16398번: 행성 연결

홍익 제국의 중심은 행성 T이다. 제국의 황제 윤석이는 행성 T에서 제국을 효과적으로 통치하기 위해서, N개의 행성 간에 플로우를 설치하려고 한다. 두 행성 간에 플로우를 설치하면 제국의 함

www.acmicpc.net

 

▲ top