Post

[ STUDY/Effective C++ ] 2022. 9. 22. 12:40

자원을 객체에 넣음으로써,  C++가 자동으로 호출해 주는 소멸자에 의해 해당 자원을 저절로 해제할 수 있다.

 

표준라이브러리에 auto_ptr클래스가 있는데, 이 클래스는 포인터와 비슷하게 동작하는 스마트포인터로서 가리키고있는 대상에 대해 소멸자가 자동으로 delete를 불러주도록 설계되어있다.

void f()
{
    Investment *pInv(createInvestment());
    //createInvestment() 는 Investment 클래스의 객체를 동적할당하고 포인터 반환함수
    ...
    delete pInv;
 }
void f()
{
    std::auto_ptr<Investment>pInv(createInvestment());
    ...
 }

위의 코드에서는 delete에 도달하기전에 빠져나갈 요소들이 분명 많아보이지만, 밑에 auto_ptr을 쓰는 경우에는 위의 코드에서 생길 수 있는 자원누출을 막을 수 있다.

 

여기서, 자원관리에 객체를 사용하는 방법의 두가지 특징을 알 수 있다.

1. 자원을 획득한 후에 자원 관리 객체에게 넘긴다.

자원획득 초기화( Resource Acquisition Is Initialization: RAII) 라는 용어가 있다. 자원획득과 자원관리 객체의 초기화가 한문장에서 이루어진다는것이다. 

2.  자원관리 객체는 자신의 소멸자를 사용해서 자원이 확실히 해제되도록 한다.

 

 

auto_ptr은 자신이 소멸될때 가리키고 있는 대상에 대해서도 자동으로 delete를 해준다. 

그렇기때문에 객체를 가리키는 auto_ptr이 둘이상이라면 자원이 두번 이상 삭제되는 결과가 나온다.

이러한 상황을 막기위해 auto_ptr객체를 복사하면 원본 객체는 null로 만든다.

 

하지만 auto_ptr을 쓰지 못하는 상황(STL 컨테이너)이라면 참조카운팅 방식 스마트 포인터(reference-counting smart pointer: RCSP)방식 또한 좋다.

가비지 컬렉션과 비슷하게 어떤 자원을 가리키는 외부 객체의 개수를 유지하고있다가 그 개수가 0이 되면 해당 자원을 자동으로 삭제하는 스마트포인터인데, 가비지 컬렉션과 다르게 서로가리키고 있는 상황에서도 없앨 수 있단게 특징이다.

 

void f()
{
    std::tr1::shared_ptr<Investment>pInv(createInvestment());
    // tr1::shared_ptr이 대표적인  RCSP이다.
    ...
 }

 

하지만 여기서 중요하게 봐야할건, auto_ptr, shared_ptr 둘다 동적으로 할당한 배열에 대해서는 쓰지 못한다. 

왜냐하면 동적으로 할당도니 배열은 vector나 string으로 대체할 수 있기때문이다.

 

 

Post

[ STUDY/코딩문제 ] 2022. 9. 14. 02:42

달팽이는 올라가고 싶다 성공다국어



시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율
0.15 초 (추가 시간 없음) (하단 참고) 128 MB 173023 48944 41413 29.346%

문제

땅 위에 달팽이가 있다. 이 달팽이는 높이가 V미터인 나무 막대를 올라갈 것이다.

달팽이는 낮에 A미터 올라갈 수 있다. 하지만, 밤에 잠을 자는 동안 B미터 미끄러진다. 또, 정상에 올라간 후에는 미끄러지지 않는다.

달팽이가 나무 막대를 모두 올라가려면, 며칠이 걸리는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 세 정수 A, B, V가 공백으로 구분되어서 주어진다. (1 ≤ B < A ≤ V ≤ 1,000,000,000)

출력

첫째 줄에 달팽이가 나무 막대를 모두 올라가는데 며칠이 걸리는지 출력한다.


풀이

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

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

	int a, b, v, day;

	cin >> a >> b >> v;
	
	int minus = a - b;
	day = (v - a) % minus;


	if (day == 0)
		day = (v-a)/minus +1;
	else
		day = (v - a) / minus + 2;

	cout << day;

}

 

 

 v(전체높이) 에다가  a(한번 올라갈때의 높이)를 빼준것에다가

하루동안 갈 수 있는 높이를 %해준다면 

 

최종도착 바로 전 상황(바로전날)을 바탕으로 거리를 계산해준다.

 

%해주었을때 0이라면 최종도착전날까지 계산했을때 남는거리가 없다라는뜻이다. 

하지만 우린 최종도착전날까지의 거리를 계산한것이므로 한번 더 가야하기때문에 +1을 해줘야한다.

 

그러나 %해주었을때 0이 아니라면 최종도착전날인데도 불구하고 아직 거리가 남아있단 뜻이다.

그러므로 최종도착날짜 (+1)에다가 남은 거리까지(+1)을 해줘야하기에 +2를 해준다.

 

날짜는 (v-a)/minus를 통해 최종도착 전날까지를 계산하고 여기에다가 최종도착날까지를 계산해서 +1을 해주는데,

남은거리가 존재한다면 +1을 한번 더 해주어 +2를 해준다.

 

 

 


내가 대학교1학년때 풀었던 문제.. 그 당시에는 for문을 돌려 하루하루를 계산했다.

#include<stdio.h>

int main() {
	int a, b, v, day;
	
	scanf("%d %d %d", &a, &b, &v);

	for (day = 1; ; day++) {
		
		v -= a;
	
		if (v <= 0)
			break;
		v += b;

	}

	printf("day = %d", day);

}

지금보니까 너무 부끄러운데.. 아무튼 정말 직관적으로 아 하루하루 날을 세면 되겠구나! 라고 생각을 하고 더하고 빼고 했던것같다 ㅎㅎㅎ;; 너무 부끄럽지만 그 당시에는 코딩에 익숙치못해서 그랬던것같다. 

한 두번정도 틀리니까 와 이문제는 어려운거구나! 라는 생각에 시도를 하지않기도했고 

지금 다시 풀어봤을때도 괜히 어렵게 꼬아서 생각을 했던것같다.

다시보니까 빙구같다...귀엽기도하고..안타깝기도하고..부끄럽네...

그래도 과거 틀렸습니다에 머무르지않고 맞았습니다로 극복했기에 이렇게 블로그에다가도 쓴다! 뿌듯하다!!😁✨

Post

[ STUDY/유니티 ] 2022. 9. 10. 18:00

메지카복셀프로그램에서 오른쪽 하단에 Export를 눌러줍니다

 

 

그런다음에 obj를 눌러줍니다

 

obj파일을 저장한 경로로 가면 이렇게 3개의 파일들이 존재합니다.

 

이 친구들(3파일 모두)을 유니티 프로젝트 폴더안, Assets밑에 원하는경로에다가 넣어줍니다. 

 

씬에다가 넣어줍니다. 그럼 캐릭터가 나옵니다!

 

저는 position에서 y=-0.3 정도를 하니까 바닥에 착 달라붙더라구여 참고참고~.~

 

Post

[ STUDY/Effective C++ ] 2022. 9. 8. 16:26

복사생성자와 복사대입연산자를 통틀어 객체 복사 함수(copy function)이라고한다. 객체 복사함수는 컴파일러가 자동으로 만들어내기도하며 복사되는 객체가 갖고있는 데이터를 빠짐없이 복사하는 동작을하고있다.

 

하지만 컴파일러가 아닌 우리가 객체 복사함수를 만드는것이 컴파일러에게는 꽤나 기분이 나쁠 수도있다. 그래서 우리에게 복사함수 구현이 틀려도 조용히 있을경우가 있다.

 

class Customer{
public:
	...
	Customner(const Customer& rhs);
	Customer& operator=(const Customer& rhs);
	...
private:
	std::string name;
};



Customer::Customer(const Customer& rhs)
: name(rhs.name) //rhs데이터 복사
{
	logCall("customer copy constructor");
}

Customer& Customer::oprator=(const Customer& rhs)
{
	loCall("Customer copy assignment operator");
	name = rhs.name; //rhs데이터 복사
	return *this;
}

복사함수를 직접 구현하였을 경우의 클래스이다. 문제될것이 없어보이지만 여기서 데이터 멤버 하나를 추가하면 문제가 생기기 시작한다.

private:
	std::string name;
	Data lastTransaction;

추가가되는 순간 이전에 있던 복사함수들은 완전 복사가 아닌 부분복사가된다. 이럴경우 우리는 클래스에 데이터 멤버를 추가하였다면 추가한 데이터 멤버를 처리하도록 복사 함수를 다시 작성해야한다.(생성자도 다시!)

 

 

그리고, 클래스를 상속한다면 조금 더 머리가 어지러워진다.

class PriorityCustomer: public Customer{
public:
	...
	PriorityCustomer(const PriorityCustomer& rhs);
	PriorityCustomer& operator=(const PriorityCustomer& rhs);
	...
private:
	int priority;
};



PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: priority(rhs.priority) //rhs데이터 복사
{
	logCall("PriorityCustomer copy constructor");
}

PriorityCustomer& PriorityCustomer::oprator=(const PriorityCustomer& rhs)
{
	loCall("PriorityCustomer copy assignment operator");
	priority = rhs.priority; //rhs데이터 복사
	return *this;
}

PriorityCustomer를 복사하는것같지만, 사실 Customer로부터 상속한 데이터 멤버들은 복사가 되지않고있다.

그나마 복사생성자에서는 Customer에서 상속한 name이나 lastTransaction을 초기화해주겠지만, 복사 대입연산자에서는 기본 클래스 데이터 멤버가 변경되지않고 그대로 있게된다.

 

PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: Customer(rhs), ////////기본 클래스의 복사 생성자 호출
	priority(rhs.priority) 
{
	logCall("PriorityCustomer copy constructor");
}

PriorityCustomer& PriorityCustomer::oprator=(const PriorityCustomer& rhs)
{
	loCall("PriorityCustomer copy assignment operator");
    ////////////////////기본 클래스 부분 대입
    Customer::operator=(rhs);
    /////////////////////
	priority = rhs.priority; 
	return *this;
}

그럴 경우에는 기본 클래스의 복사 생성자를 호출하거나, 기본 클래스 부분을 대입하면된다. 객체 복사함수는 주어진 객체의 모든 데이터 멤버 및 모든 기본 클래스 부분을 빠트리지말고 복사해야한다. 

▲ top