C ++에서 포인터에 대한 참조 전달


130

내가 알 수있는 한, C ++에서 포인터에 대한 참조를 전달해서는 안되는 이유가 없습니다. 그러나 그렇게하려는 시도가 실패하고 이유를 모릅니다.

이것이 내가하고있는 일입니다.

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

그리고 나는이 오류가 발생합니다 :

'std :: string *'에서 'std :: string * &'로 매개 변수 1을 변환 할 수 없습니다.

답변:


126

함수는 익명 문자열 포인터가 아닌 호출 범위의 실제 문자열 포인터에 대한 참조를 기대합니다. 그러므로:

string s;
string* _s = &s;
myfunc(_s);

잘 컴파일해야합니다.

그러나 이것은 함수에 전달하는 포인터를 수정하려는 경우에만 유용합니다. 문자열 자체를 수정하려면 Sake가 제안한대로 문자열에 대한 참조를 사용해야합니다. 이를 염두에두고 컴파일러가 원래 코드에 대해 불평하는 이유가 더 분명해야합니다. 코드에서 포인터는 '즉석에서'만들어 지므로 포인터를 수정해도 아무런 결과가 없으며 의도 한 것이 아닙니다. 참조 (포인터 대)의 아이디어는 참조가 항상 실제 객체를 가리키는 것입니다.


86

문제는 임시 참조를 참조에 바인딩하려고하는데 참조가 아닌 경우 C ++에서 허용하지 않습니다 const.

따라서 다음 중 하나를 수행 할 수 있습니다.

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}


void myfunc2(string* const& val)
{
    // Do stuff to the string pointer
}

int main()
// sometime later 
{
    // ...
    string s;
    string* ps = &s;

    myfunc( ps);   // OK because ps is not a temporary
    myfunc2( &s);  // OK because the parameter is a const&
    // ...

    return 0;
}

Mr. Burr가 예를 들어 2 string* const& val와 같이 덜 읽기 쉬운 대신에 No.2의 방식을 작성하는 것이 특히 유익합니다 const string* &val. 내 눈에 이것은 분명히 const 참조 , 포인터, 문자열에 대한 것입니다. 나는 이 정확한 설명을 얻기 위해 선언 T const&대신 글을 쓰는 것을 선호합니다 const T&.
fish2000

1
Nit pick (비평이 아님) : bind a temporary to the reference이 대답에서 @Chris 'as보다 문구 가 더 명확 reference to an actual string pointer in the calling scope, not an anonymous string pointer합니다. 어쨌든, 내 관점에서 둘 다 맞을 것입니다.
kevinarpe

1
@ fish2000뿐만 아니라, const string*&그리고 string* const&실제로 다른 유형입니다. 첫 번째는 비이다 const(A)에 기준 const string*번째는 반면, const(A)에 대한 참조 string*.
저스틴 타임-복원 모니카

@ fish2000 은 @Justin Time이 지적한 바와 같이 "선호" T const&에 주의해야 const T&합니다. 때로는 결과가 없을 수도 있지만, 다른 상황에서는 선호하는 것보다 하나를 선호하는 것이 절대적으로 중요 int합니다 double.
omatai

3
@ fish2000-하나는 "변경할 수없는 것으로 변경할 수있는 참조가 있습니다"라고 말하고 다른 하나는 "변경할 수없는 것으로 변경할 수없는 참조가 있습니다"라고 말합니다. 이 예제에서는 단순히 둘을 교환 할 수 없습니다.
omatai

10

다음으로 변경하십시오.

  std::string s;
  std::string* pS = &s;
  myfunc(pS);

편집하다:

이것은 호출 ref-to-pointer되며 함수에 대한 참조로 임시 주소를 전달할 수 없습니다. (이 아닌 경우 const reference).

비록 std::string* pS = &s;(지역 변수에 대한 포인터)를 보여 주었지만, 일반적인 사용법은 다음과 같습니다. 피 호출자가 가리키는 객체가 아닌 포인터 자체를 변경하기를 원할 때. 예를 들어, 메모리를 할당하고 인수에 할당 된 메모리 블록의 주소를 할당하는 함수는 포인터 또는 포인터에 대한 포인터를 참조해야합니다.

void myfunc(string*& val)
{
//val is valid even after function call
   val = new std::string("Test");

}

5

&s 문자열에 대한 임시 포인터를 생성하고 임시 객체를 참조 할 수 없습니다.


4
이것은 사실이 아닙니다-const 임시 참조를 할 수 있습니다
1800 INFORMATION

3

시험:

void myfunc(string& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(s);
    // ...
}

또는

void myfunc(string* val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

그래도 내가하고있는 일에 대해서는 포인터 자체뿐만 아니라 포인터의 주소가 필요합니다. 값으로 포인터를 전달하고 싶지 않습니다.
Alex

아직도 당신이 성취하려고하는 것을 이해하지 못합니다. "문자열 s"가 포인터가 아니기 때문에 "문자열 s"의 "포인터 주소"를 가질 수 없습니다.
Sake

@ 알렉스 : 문자열이 내용이 같은지 여부가 아니라 저장하는 다른 문자열과 정확히 같은지 여부를 감지해야한다고 생각합니다. 이 경우 address-of 연산자를 참조에 사용할 수 있으며 참조 된 객체의 주소를 얻을 수 있습니다. void f (std :: string const & s) {std :: string const * p = & s; }
David Rodríguez-dribeas

3

편집 : 나는 몇 가지를 실험하고 생각보다 조금 미묘한 것을 발견했습니다. 내가 지금 생각하는 것이 정답입니다.

&s는 lvalue가 아니므로 참조 유형이에 대한 참조가 아니면 참조를 작성할 수 없습니다 const. 예를 들어, 당신은 할 수 없습니다

string * &r = &s;

하지만 넌 할 수있어

string * const &r = &s;

함수 헤더에 비슷한 선언을 넣으면 작동합니다.

void myfunc(string * const &a) { ... }

또 다른 문제, 즉 임시 문제가 있습니다. 규칙은 임시 인 경우에만 참조를 얻을 수 있다는 것입니다 const. 따라서이 경우 & s는 일시적이라고 선언 할 수 있으므로 선언해야합니다.const 함수 프로토 타입에서 . 실제적인 관점에서이 경우에는 차이가 없습니다. (rvalue 또는 임시입니다. 어느 쪽이든 같은 규칙이 적용됩니다.) 그러나 엄밀히 말하면, 나는 그것이 일시적이 아니라 rvalue라고 생각합니다. 두 가지를 구별 할 수있는 방법이 있는지 궁금합니다. (아마도 모든 임시는 rvalue이고, 비 lvalue는 임시 인 것으로 정의되어 있습니다. 저는 표준 전문가가 아닙니다.)

즉, 귀하의 문제는 아마도 더 높은 수준 일 것입니다. 의 주소에 대한 참조를 원하는 이유는 무엇 s입니까? 에 대한 포인터를 참조하려면 다음과 같이 포인터 s를 정의해야합니다.

string *p = &s;
myfunc(p);

에 대한 참조 s또는 포인터를 원하면 s간단한 작업을 수행하십시오.


1

방금 루트 안전을 제외하고 삭제 된 이진 트리의 모든 포인터를 만들기 위해 포인터에 대한 참조를 사용했습니다. 포인터를 안전하게 만들려면 그냥 0으로 설정해야합니다. 루트 (이 포인터)를 첫 번째로 사용하고 있기 때문에 트리를 삭제하는 기능 (루트 만 유지)을 포인터에 대한 참조를 허용하는 함수를 만들 수 없습니다 왼쪽과 오른쪽을 통과하는 입력.

void BinTree::safe_tree(BinTree * &vertex ) {
    if ( vertex!=0 ) {  // base case
        safe_tree(vertex->left);    // left subtree.
            safe_tree(vertex->right);   //  right subtree.
          // delete vertex;  // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
        vertex=0;  // making a safe pointer
    }
} // end in

결론적으로, 공식 매개 변수가 (this) 포인터 인 경우 포인터에 대한 참조는 유효하지 않습니다.


1

C ++ 11 및 rvalue 참조에 오신 것을 환영합니다 :

#include <cassert>
#include <string>

using std::string;

void myfunc(string*&& val)
{
    assert(&val);
    assert(val);
    assert(val->c_str());
    // Do stuff to the string pointer
}

// sometime later 
int main () {
    // ...
    string s;
    myfunc(&s);
    // ...
}

이제 val문자열 주소 인 포인터 값 (에 의해 참조 됨 )에 액세스 할 수 있습니다 .

포인터를 수정할 수 있으며 아무도 신경 쓰지 않습니다. 이것이 rvalue가 무엇인지에 대한 한 측면입니다.

주의 : 포인터 값은 myfunc()반환 될 때까지만 유효 합니다. 마침내 일시적입니다.


-1

포인터의 참조를 전달하는 것이 가능하다는 것을 알고 있습니다. 지난주에했지만 코드가 내 뇌에 맞아 보이기 때문에 구문이 무엇인지 기억할 수 없습니다. 그러나 다른 옵션은 포인터의 포인터를 사용하는 것입니다.

Myfunc(String** s)

-8

myfunc ( "string * & val") 이것 자체는 의미가 없습니다. "string * & val"은 "string val"을 의미하며 *는 서로를 취소합니다. 마지막으로 문자열 변수를 함수 ( "string val")에 전달할 수 없습니다. 다른 데이터 유형은 포인터 또는 참조로 전달해야하므로 기본 데이터 유형 만 함수에 전달 될 수 있습니다. string & val 또는 string * val을 함수에 가질 수 있습니다.


4
모든 수준에서 잘못되었습니다. var 선언 구문을 새로 고치십시오.
Ari
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.