이것은 내가 생각하는 약간 주관적입니다. 의견이 만장일치인지 확실하지 않습니다 (참조가 반환되는 많은 코드 스 니펫을 보았습니다).
이 질문 에 대한 의견에 따르면 , 참조 초기화와 관련하여 방금 요청한 참조를 삭제하는 것이 더 쉽게 누락되어 메모리 누수가 발생할 수 있으므로 참조 를 반환하는 것은 악의적 일 수 있습니다.
나는 내가 예제를 따르고 (내가 상상하지 않는 한) 공정한 몇 곳에서 이것을 했으므로 걱정이됩니다 … 오해 했습니까? 사악한가요? 그렇다면 얼마나 악한가?
필자는 C ++을 처음 접했다는 사실과 결합 된 포인터와 참조가 혼합되어 있기 때문에 언제 사용해야 할 지에 대한 혼란이 내 응용 프로그램에서 메모리 누수 문제라고 생각합니다.
또한 스마트 / 공유 포인터 사용은 일반적으로 메모리 누수를 피하는 가장 좋은 방법으로 받아 들여진다는 것을 알고 있습니다.
답변
일반적으로 참조 반환은 완벽하게 정상이며 항상 발생합니다.
당신이 의미하는 경우 :
int& getInt() {
int i;
return i; // DON'T DO THIS.
}
그것은 모든 종류의 악입니다. 스택 할당 i
이 사라지고 아무것도 언급하지 않습니다. 이것은 또한 악하다 :
int& getInt() {
int* i = new int;
return *i; // DON'T DO THIS.
}
이제 클라이언트는 결국 이상한 일을해야하기 때문에 :
int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt; // must delete...totally weird and evil
int oops = getInt();
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original
rvalue 참조는 여전히 참조 일 뿐이므로 모든 악의적 인 응용 프로그램은 동일하게 유지됩니다.
함수의 범위를 벗어나는 것을 할당하려면 스마트 포인터 (또는 일반적으로 컨테이너)를 사용하십시오.
std::unique_ptr<int> getInt() {
return std::make_unique<int>(0);
}
이제 클라이언트는 스마트 포인터를 저장합니다.
std::unique_ptr<int> x = getInt();
다음과 같이 수명이 더 높은 수준으로 공개되어있는 것을 액세스하는 경우에도 참조가 가능합니다.
struct immutableint {
immutableint(int i) : i_(i) {}
const int& get() const { return i_; }
private:
int i_;
};
여기서 우리 i_
가 호출하는 것이 클래스 인스턴스의 수명을 관리하므로 i_
적어도 그 수명을 유지 하기 때문에 참조를 반환해도 괜찮습니다 .
그리고 물론, 단지 아무 문제가 없습니다 :
int getInt() {
return 0;
}
평생을 발신자에게 맡겨야하고 가치를 계산하는 것입니다.
요약 : 호출 후 객체의 수명이 끝나지 않으면 참조를 반환해도됩니다.
답변
아냐 아냐 아냐 아냐
악의적 인 것은 동적으로 할당 된 객체를 참조하고 원래 포인터를 잃는 것입니다. 당신 new
이 물건을 할 때 당신 은 보장을받을 의무가 있다고 가정합니다 delete
.
그러나 예를 들어 operator<<
: 참조 를 반환 해야하는 것을 보거나
cout << "foo" << "bar" << "bletch" << endl ;
작동하지 않습니다.
답변
즉시 사라지지 않고 소유권 이전을 원하지 않는 기존 객체에 대한 참조를 반환해야합니다.
로컬 변수 또는 그와 같은 일부에 대한 참조는 반환하지 않으므로 절대로 반환하지 마십시오.
함수와 무관 한 것에 대한 참조를 리턴 할 수 있으며, 호출 함수가 삭제를 담당하지 않을 것으로 예상됩니다. 일반적인 operator[]
기능 의 경우입니다 .
무언가를 생성하는 경우 값 또는 포인터 (일반 또는 스마트)를 반환해야합니다. 호출 함수에서 변수 또는 표현식으로 들어가므로 값을 자유롭게 리턴 할 수 있습니다. 로컬 변수에 대한 포인터는 반환되지 않으므로 절대 반환하지 마십시오.
답변
답변이 만족스럽지 않아서 2 센트를 더하겠습니다.
다음과 같은 경우를 분석해 봅시다.
잘못된 사용법
int& getInt()
{
int x = 4;
return x;
}
이것은 분명히 오류입니다
int& x = getInt(); // will refer to garbage
정적 변수와 함께 사용
int& getInt()
{
static int x = 4;
return x;
}
정적 변수는 프로그램 수명 기간 동안 존재하기 때문에 이것이 맞습니다.
int& x = getInt(); // valid reference, x = 4
싱글 톤 패턴을 구현할 때도 매우 일반적입니다.
Class Singleton
{
public:
static Singleton& instance()
{
static Singleton instance;
return instance;
};
void printHello()
{
printf("Hello");
};
}
용법:
Singleton& my_sing = Singleton::instance(); // Valid Singleton instance
my_sing.printHello(); // "Hello"
연산자
표준 라이브러리 컨테이너는 참조를 반환하는 연산자의 사용에 크게 의존합니다 (예 :
T & operator*();
다음에서 사용될 수 있습니다
std::vector<int> x = {1, 2, 3}; // create vector with 3 elements
std::vector<int>::iterator iter = x.begin(); // iterator points to first element (1)
*iter = 2; // modify first element, x = {2, 2, 3} now
내부 데이터에 빠르게 액세스
내부 데이터에 빠르게 액세스하기 위해 &를 사용하는 경우가 있습니다
Class Container
{
private:
std::vector<int> m_data;
public:
std::vector<int>& data()
{
return m_data;
}
}
사용법 :
Container cont;
cont.data().push_back(1); // appends element to std::vector<int>
cont.data()[0] // 1
그러나 이것은 다음과 같은 함정으로 이어질 수 있습니다.
Container* cont = new Container;
std::vector<int>& cont_data = cont->data();
cont_data.push_back(1);
delete cont; // This is bad, because we still have a dangling reference to its internal data!
cont_data[0]; // dangling reference!
답변
악하지 않습니다. C ++의 많은 것들과 마찬가지로 올바르게 사용하면 좋지만 지역 변수에 대한 참조를 반환하는 것과 같이 사용할 때 알아야 할 많은 함정이 있습니다.
그것으로 달성 할 수있는 좋은 것들이 있습니다 (예 : map [name] = “hello world”)
답변
“참조를 반환하는 것은 악의적이다. 왜냐하면 단순히 [이해 한 것처럼] 그것을 삭제하기가 더 쉽기 때문이다”
사실이 아니다. 참조를 반환한다고해서 소유권 의미가있는 것은 아닙니다. 즉, 당신이 이것을하기 때문에 :
Value& v = thing->getTheValue();
… v가 참조하는 메모리를 소유한다는 의미는 아닙니다.
그러나 이것은 끔찍한 코드입니다.
int& getTheValue()
{
return *new int;
}
“해당 인스턴스에 포인터가 필요하지 않기 때문에 “ 이와 같은 작업을 수행하는 경우 1) 참조가 필요한 경우 포인터를 역 참조하고 2) 결국 포인터가 필요합니다. 새로운 삭제, 당신은 삭제 호출 포인터가 필요합니다.
답변
두 가지 경우가 있습니다.
-
const reference-때로는 무거운 객체 또는 프록시 클래스, 컴파일러 최적화에 대한 좋은 아이디어
-
비 const 참조-때로는 나쁜 생각으로 캡슐화가 깨짐
둘 다 동일한 문제를 공유합니다-잠재적으로 파괴 된 객체를 가리킬 수 있습니다 …
참조 / 포인터를 반환 해야하는 많은 상황에서 스마트 포인터를 사용하는 것이 좋습니다.
또한 다음 사항에 유의하십시오.
C ++ 표준 (관심있는 경우 섹션 13.3.3.1.4)에 임시 규칙은 const 참조에만 바인딩 할 수 있다고 공식적인 규칙이 있습니다-비 const 참조를 사용하려고하면 컴파일러는이 플래그를 오류.