프로그래밍 언어/C++

[C++] 임시(temporary) 객체

까망 하르방 2025. 4. 26. 15:22
반응형

임시 객체

• Point p1(1, 2) ;
→ named object 
→ 선언한 블록을 벗어날 때 파괴

• Point(3, 4);
→ 임시 객체 (unnamed object)
→ 선언한 문장의 끝에서 파괴

#include <iostream>

struct Point
{
	int x, y;
	Point(int a = 0, int b = 0) { std::cout << "Point()" << std::endl; }
	~Point() { std::cout << "~Point()" << std::endl; }
};

int main()
{
	// Point p1(1, 2);	//  named object
	Point(3, 4); // unamed object (= temporary)
	
	std::cout << "----------" << std::endl;
}

 


문장 끝나자마자 소멸되는 것을 확인할 수 있다.


[예제] 임시객체 특징

• 임시 객체는 rvalue로 등호(=)의 왼쪽에 올 수 없다.
• 임시 객체는 주소를 구할 수 없다. (생성자에서 this 사용할 수 있다.)

#include <iostream>

using namespace std;

struct Point
{
	int x, y;
	Point(int a = 0, int b = 0) { cout << "Point()" << endl; }
	~Point() { cout << "~Point()" << endl; }
};

int main()
{
	Point p1; // named object

	p1.x = 10;	// ok
	Point().x = 10;	// ?? -> error


	Point* pp1 = &p1;	// ok
	Point* pp2 = &Point();	// ?? -> error
}



[예제 코드]
const  reference는 임시 객체를 참조할 수 있다.
non-const reference는 임시 객체를 참조할 수 없다.

C++11에서 rvalue reference는 상수성 없이 rvalue 가리킬 수 있다.

#include <iostream>

using namespace std;

struct Point
{
	int x, y;
	Point(int a = 0, int b = 0) { cout << "Point()" << endl; }
	~Point() { cout << "~Point()" << endl; }
};

int main()
{
	Point p1; // named object

	const Point& r3 = p1;		// ok
	const Point& r4 = Point();	// ?? -> ok

	Point& r1 = p1;		// ok
	Point& r2 = Point();	// ?? -> error

	Point&& r5 = p1;       // ?? -> error, rvalue reference 는 rvalue만 가리킬수 있다.
	Point&& r6 = Point(); // ok
}

임시 객체 함수 인자 전달

foo 함수에 전달하는 용도로만 객체를 사용한다고 가정해보자.
Point p 는 함수 전달 후에는 사용하지 않는데
블록을 벗어날 때까지 소멸되지 않는다.

#include <iostream>

using namespace std;

struct Point
{
	int x, y;
	Point(int a = 0, int b = 0) { cout << "Point()" << endl; }
	~Point() { cout << "~Point()" << endl; }
};

// 임시객체와 함수 인자
void foo(const Point& p) { }

int main()
{
	Point p(1, 1);
	foo(p);
	cout << "----- end -----" << endl;
}



main 함수가 끝나고 소멸되는 Point p



함수 인자로 전달하는 목적으로만 사용한다면
임시 객체로 전달해야
불필요한 메모리 낭비를 줄일 수 있다.

 


[예제 코드]
임시 객체를 바로 인자로 전달하는 경우
이 경우 함수 인자는 반드시 const Point& 형태로 받아야 한다.

#include <iostream>
using namespace std;

struct Point
{
	int x, y;
	Point(int a = 0, int b = 0) { cout << "Point()" << endl; }
	~Point() { cout << "~Point()" << endl; }
};

// 임시객체와 함수 인자
void foo(const Point& p) { }

int main()
{
	foo(Point(1, 1));
	cout << "----- end -----" << endl;
}

값 리턴 vs 참조 리턴

• return by value 리턴용 임시객체 반환
• return by reference 리턴용 임시객체 생성하지 않는다.

#include <iostream>

using namespace std;

struct Point
{
	int x, y;
	Point(int a = 0, int b = 0) { cout << "Point()" << endl; }
	~Point() { cout << "~Point()" << endl; }
};

Point pt(1, 1);

Point f1() // return by value
{
	return pt;
}

Point& f2() // return by reference
{
	return pt;
}

int main()
{
	f1().x = 10; // ?? -> error
	f2().x = 10; // ?? -> ok
}



지역 변수를 반환하는 경우
블록을 벗어나면 파괴되기 때문에
return by reference 하는 경우 위험하다.

Point& f3() // return by reference
{
	Point pt(2, 2);
	return pt;
}

temporary와 타입 캐스팅

#include <iostream>

using namespace std;

struct Base
{
	int v = 10;

	Base() = default;
	Base(const Base& b) : v(b.v)
	{
		cout << "생성자" << endl;
	}
};

struct Derived : public Base
{
	int v = 20;
};

int main()
{
	Derived d;
	cout << d.v << endl; // 20

	cout << (static_cast<Base>(d)).v << endl; // 10
	cout << (static_cast<Base&>(d)).v << endl; // 10
}



static_cast<Base>(d)).v 와 static_cast<Base&>(d)).v 결과는 같지만
임시객체를 이해하면 다른 원리가 있는 것을 짐작할 수 있다.

static_cast<Base> 의 경우 임시 객체를 생성하고
static_cast<Base&>는 임시 객체를  생성하지 않는다.

(static_cast<Base>(d)).v = 30; // ?? -> error
(static_cast<Base&>(d)).v = 30; // ?? -> ok
반응형