source

C와 C++의 "기준 통과"의 차이는 정확히 무엇입니까?

nicesource 2023. 10. 26. 21:14
반응형

C와 C++의 "기준 통과"의 차이는 정확히 무엇입니까?

"pass by reference"라는 문구는 C와 C++ 개발자들이 동일하게 사용하고 있지만 서로 다른 의미로 사용되고 있는 것으로 보입니다.각 언어에서 이 애매모호한 문구의 차이는 정확히 무엇입니까?

기준 통과와 값 통과의 차이를 이미 다루는 질문들이 있습니다.기본적으로, 함수에 값별로 인수를 전달한다는 것은 함수가 자체적으로 인수 복사본을 갖게 된다는 것을 의미합니다. 즉, 함수의 값이 복사됩니다.해당 복사본을 수정해도 원래 개체는 수정되지 않습니다.그러나 참조를 통과할 때 함수 내부의 매개 변수는 전달된 개체와 동일한 개체를 나타냅니다. - 함수 내부의 모든 변화는 외부에서 볼 수 있습니다.

유감스럽게도 "pass by value"와 "pass by reference"라는 두 가지 문구가 사용되어 혼동을 일으킬 수 있습니다.이것이 부분적으로 C++ 프로그래머들이 새로운 C++ 프로그래머들이 채택하기 어려운 이유라고 생각합니다. 특히 C의 배경에서 왔을 때 말이죠.

C

C에서는 기술적인 의미에서 모든 것이 가치에 의해 통과됩니다.즉, 함수에 대한 인수로 무엇을 주든지 해당 함수에 복사됩니다.예를 들어 함수 호출하기void foo(int)와 함께foo(x)의 가치를 베끼다x의 매개 변수로서foo 예에서 할 수 이는 간단한 예에서 확인할 수 있습니다.

void foo(int param) { param++; }

int main()
{
  int x = 5;
  foo(x);
  printf("%d\n",x); // x == 5
}

의 입니다.x로 복사됩니다.foo그리고 그 복사본은 증가하고 있습니다.x인에main원래의 가치를 계속 유지하고 있습니다.

알고 계시겠지만, 오브젝트는 포인터 타입일 수 있습니다.예를들면,int* p정의합니다.p의 지시자로서int는 두 다음 코드는 두 개의 객체를 소개합니다.

int x = 5;
int* p = &x;

첫번째는 유형입니다.int그리고 가치가 있습니다.5. 두번째는 유형입니다.int*그리고 그 값은 첫번째 개체의 주소입니다.

함수에 포인터를 전달할 때 여전히 값으로 포인터를 전달하고 있습니다.포함된 주소가 함수에 복사됩니다.함수 내부의 포인터를 수정해도 함수 외부의 포인터는 변경되지 않습니다. 그러나 함수가 가리키는 개체를 수정하면 함수 외부의 개체가 변경됩니다.하지만 왜 그랬을까?

동일한 값을 가진 두 포인터가 항상 동일한 개체(동일한 주소를 포함함)를 가리키기 때문에 두 포인터를 모두 통해 가리키는 개체에 액세스하고 수정할 수 있습니다.이것은 참조를 통해 개체를 가리킨 것에 대한 의미론을 제공합니다. 비록 참조가 실제로 존재하지는 않았지만 - 단순히 C에는 참조가 없습니다.변경된 예를 살펴봅니다.

void foo(int* param) { (*param)++; }

int main()
{
  int x = 5;
  foo(&x);
  printf("%d\n",x); // x == 6
}

우리는 그것을 통과할 때 말할 수 있습니다.int*기능으로, 그것은.int그것은 "참조에 의해 통과되었다"고 지적하지만, 사실은.int실제로는 아무 곳에도 전달되지 않았습니다. 오직 포인터만이 함수에 복사되었습니다.이것은 우리에게 "pass by value"와 "pass by reference"라는1 구어적 의미를 부여합니다.

이 용어의 사용은 표준에 포함된 용어로 뒷받침됩니다.포인터 유형이 있는 경우, 포인터 유형이 가리키는 유형을 참조된 유형이라고 합니다.즉, 참조되는 유형은int*이다.int.

포인터 유형은 함수 유형, 개체 유형 또는 참조된 유형이라고 하는 불완전한 유형에서 파생될 수 있습니다.

단 하나뿐인 동안*연산자(에서와 같이)*p는 해제라고도 는 표준에서 간접이라고도 하며, 일반적으로 포인터를 역참조라고도 합니다.이것은 C의 "기준 통과" 개념을 더욱 촉진합니다.

C++

C++는 C의 많은 독창적인 언어 기능을 채택했습니다.그 중에는 포인터가 있으므로 "참조로 전달"이라는 구어체 형식은 여전히 사용할 수 있습니다.*p아직도 재참조 중입니다p. 그러나 C++는 C가 가지고 있지 않은 기능, 즉 참조를 진정으로 통과하는 기능을 도입하기 때문에 이 용어를 사용하는 것은 혼란스러울 것입니다.

유형 뒤에 앰퍼샌드가 오는 것이 기준 유형입니다2.예를들면,int&에 대한 언급입니다.int 참조 유형을 취하는 함수에 인수를 전달할 때 개체는 참조를 통해 진정으로 전달됩니다.포인터도 없고, 객체 복사도 없고, 아무것도 없습니다.함수 내부의 이름은 실제로 전달된 개체와 정확히 동일한 개체를 나타냅니다.위의 예와 대비하기:

void foo(int& param) { param++; }

int main()
{
  int x = 5;
  foo(x);
  std::cout << x << std::endl; // x == 6
}

.foo함수는 다음과 같은 참조인 매개 변수를 갖습니다.int. 이제 지나갈때x,param정확히 동일한 개체를 가리킵니다.점증하는param의 값에 눈에 보이는 변화가 있습니다.x그리고 지금x값이 6입니다.

이 예제에서는 값으로 전달된 것이 없습니다.아무것도 복사되지 않았습니다.기준을 통과하는 것이 실제로 값으로 포인터를 통과하는 것이었던 C와는 달리, C++에서는 기준을 통과할 수 있습니다.

참조 통과라는 용어에서는 이러한 모호성이 존재하기 때문에 참조 유형을 사용할 때는 C++의 맥락에서만 사용하는 것이 좋습니다.포인터를 전달하는 경우 참조를 전달하는 것이 아니라 값을 기준으로 포인터를 전달하는 것입니다(예: 포인터에 참조를 전달하는 경우가 아니라면).int*& 때 통과을 우연히 도 있지만,은 실제로 있는지 그러나 포인터가 사용되고 있을 때 "기준 통과"라는 용어를 접할 수도 있지만 적어도 지금은 실제로 무슨 일이 일어나고 있는지 알고 있습니다.


타국어

다른 프로그래밍 언어는 일을 더욱 복잡하게 만듭니다.Java와 같은 일부 변수에서는 개체에 대한 참조(C++의 참조와 동일하지 않음)로 모든 변수가 알려져 있지만 이러한 참조는 값으로 전달됩니다.참조를 통해 함수를 전달하는 것처럼 보이지만 실제로 수행하는 작업은 값을 기준으로 함수에 참조를 복사하는 것입니다.C++에서 기준 통과에 대한 미묘한 차이는 전달된 기준에 새 객체를 할당할 때 알 수 있습니다.

public void foo(Bar param) {
  param.something();
  param = new Bar();
}

자바에서 이 함수를 호출한다면, 어떤 종류의 객체를 전달하는 것입니다.Bar, 로의 부름param.something()당신이 통과한 것과 같은 대상에서 호출될 겁니다개체에 대한 참조를 전달했기 때문입니다.그러나, 비록 새로운 것일지라도,Bar에 할당됩니다.param, 함수 외부의 개체는 여전히 이전 개체와 같습니다.새것은 외부에서 전혀 보이지 않습니다.그건 내부의 참조가foo새 개체로 재할당됩니다.이런 종류의 레퍼런스 재할당은 C++ 레퍼런스에서는 불가능합니다.


1 "구어적"으로, 저는 "기준 통과"의 C 의미가 C++의 의미보다 덜 진실하다고 주장하려는 것은 아닙니다. 단지 C++가 정말로 기준 유형을 가지고 있으므로 당신이 정말로 기준을 통과하고 있다는 것입니다.C의 의미는 실제로 가치를 전달하고 있는 것에 대한 추상화입니다.

2 물론, 이것들은 lvalue reference들이고 우리는 이제 C++11에도 rvalue reference들이 있습니다.

언급URL : https://stackoverflow.com/questions/13654138/what-exactly-is-the-difference-between-pass-by-reference-in-c-and-in-c

반응형