[완료] c++ 함수 파라메터에 *& 가 붙어있을때 어떻게 전해줘야 하나요?

kleinstein의 이미지

//

any_function(int *& num);

//

위와 같이 어떤 함수가 int *& 타입의 파라메터(리턴 값으로)를 요구하면 저 함수를 부르는 입장에서 어떻게 저 파라메터를 보내줘야 하나요?

제가 몇가지 생각해봤는데요..

1.
int a;
int * b = &a;
any_function(b);

2.
int a;
any_function(&a);

3.
int* a = 0;
any_function(a);

더 이상은 어떻게 준비시켜서 넘겨줘야 할지 생각이 안나네요..

그리고 또 왜 이런형식의 파라메터가 생겨나는건지요?

klyx의 이미지

int*를 넘기면 됩니다.

kleinstein의 이미지

3번 처럼 하니까 넘겨준 파라메터에 메모리 릭이 생기는데요?

어떻게 해줘야 하는건지요?

함수를 부르고 난다음 넘겨줬던 파라메터를 delete 로 지워야 하나요?

만약 delete 로 지우면 release 모드에서 프로그램이 그냥 에러가 나면서 다운되어 버리거든요..

그렇다고 안지우면 메모리 릭이 생기고..

int* 를 넘기는게 정말 맞는건가요???

klyx의 이미지

그건 any_function이 어떻게 동작하느냐의 문제이지, 파라메터의 형이 안맞기 때문이 아닙니다.
any_function이 어떤함수인지를 알아야 왜 메모리릭이 생기는지를 알수 있습니다.
그리고 1, 3 은 맞습니다.
(2번도 맞다고 적었었는데, 아래분 말씀대로 const가 아니라서 안됩니다. 보통 참조자로 넘길땐 거의가 const로 넘기기때문에 착각하고 잘못적었었습니다. 죄송합니다.)
마지막에 달은 '왜 이런게 있나'라는 질문은, C++의 참조(reference)에 대해 찾아보시는게 좋을 것같습니다.

doldori의 이미지

함수의 인자가 int* 형에 대한 참조형인 것입니다.
typedef를 써서 약간 바꿔보면 이해가 쉬울지도 모르겠습니다.

typedef int* int_ptr;
 
void by_reference(int_ptr& p)
{
    p = new int;
}
 
int main()
{
    int_ptr p;
    by_reference(p);
    delete p;
}

위의 코드는 다음과 같은 효과를 갖습니다.
void by_pointer_to_pointer(int** p)
{
    *p = new int;
}
 
int main()
{
    int* p;
    by_pointer_to_pointer(&p);
    delete p;
}

그리고 2번은 틀립니다.
non-const 참조형 인자는 lvalue만 가능한데 주소연산자 &를 취한 결과는 lvalue가 아니기 때문입니다.

kleinstein의 이미지

두번째에 설명해주신 by_pointer_to_pointer(&p); 에서 &p 라는건 결국 *& 가 아니고 &* 아닌가요?
아니면 *& 과 &* 사이에 차이가 없는 건가요?

여전히 잘 이해가 되지 않는군요.. 첫번째로 설명해주신 코드의 경우라면 왜 ** 을 쓰지 않고 굳이 *& 를 한건가요??

kleinstein의 이미지

typedef int* int_ptr;
 
void by_reference(int_ptr& p)
{
    p = new int;
}
 
int main()
{
    int_ptr p;
    by_reference(p);
    delete p;
}

의 경우 *& 을 넘겨준게 아니고 결국 &* 형을 넘겨준거 아닌가요?

klyx의 이미지

에... 참조에 대해 한번 훓어보시는걸 추천드리지만, 간단하게 말씀드리면, (그 구현이실제로는 포인터이든 어떻든간에)참조는 변수에 별명을 다는 셈입니다.
포인터를 넣지 말고 int a; int &b = a; 라고 하고 b = 4; 라고 하면 a를 직접 조작하지 않고 a의 값을 4로 변경하게 됩니다.
C에서는 이렇게 할려면 int a; int *b = &a; 라고 한후, *b = 4 라고 해야되지요.
결국 참조자로 하는건 포인터로도 할 수 있습니다만, 포인터로 할 수 있는 것 중엔 참조자로할 수 없는게 있습니다(포인터는 널값을 가질수 있죠).
그럼 왜 참조자가 있냐하면, 의미상 좀더 적합하고, 쓰기 편하고, 간결하기 때문입니다.
당연히 위의 경우 **로도 가능하지만, 이렇게 하면 이중 포인터가 되므로 쓰기가 불편할 수도 있겠구요...하지만 이런건 프로그래머맘이므로 쓰고싶은걸 쓰면됩니다(언제 참조를 쓰고 언제포인터를 쓰느냐만으로 여러가지 논의가 있으므로 한번 찾아보시면 도움될 것 같습니다.)
그리고 *&가 아니라 &*이라고 생각하신 이유가 무엇인지요?(참고로 &*이라는 형은 없습니다)

kleinstein의 이미지

typedef int* int_ptr;
 
void by_reference(int_ptr& p)
{
    p = new int;
}
 
int main()
{
    int_ptr p;
    by_reference(p);
    delete p;
}

의 경우 위의 typedef int* int_ptr; 부분을 그대로 적용시켜서 다음과 같이 바꿔주면

void by_reference(int*& p)
{
    p = new int;
}
 
int main()
{
    int* p;
    by_reference(p);
    delete p;
}

아예 컴파일도 되지 않습니다. ** 을 *& 형으로 바꿔서 넣을수 없다는 에러가 납니다.

klyx의 이미지

전 에러 없이 잘 되는데요...-_-;gcc(g++) 4.1.3에서 컴파일 했습니다.

kleinstein의 이미지

저의 경우 메모리 릭이 생깁니다.

위의 모든 예제는 그저 int 타입 클래스여서 그런지도 모르겠군요..

제 실제 코드를 붙여서 다시 한번 여쭤보고 싶습니다.

        SPAinterval* tmpItvp = 0;
        int num = curV->equation().high_curvature(0.00001,tmpItvp);
        if (tmpItvp != 0)
        {
            delete tmpItvp; // 이 라인을 없애면 debug 모드에서 메모리릭 발생, 없애지않고 그대로 두면 release 모드에서 크래쉬 발생.
        }                                         

위와 같이 둘다 모두 에러가 생겨서 혹시 내가 뭔가를 잘못 이해하고 있나 해서 여쭤본겁니다.
혹시 다르게 파라메터를 전해줘야 하나 해서 말이죠..

아.. 정말 무슨 문제인지 모르겠네요..

klyx의 이미지

        SPAinterval* tmpItvp = 0;
        int num = curV->equation().high_curvature(0.00001,tmpItvp);
        if (tmpItvp != 0)
        {
            delete tmpItvp; // 이 라인을 없애면 debug 모드에서 메모리릭 발생, 없애지않고 그대로 두면 release 모드에서 크래쉬 발생.
        }                                         

여기서 equation().high_curvature 이 함수의 동작이 어떤지 모르면 뭐라고 하기 힘듭니다.
아마도 delete하지 않으면 메모리릭이 발생한다는 걸로 봐선 equation().high_curvature내에서 동적할당이 일어나는 듯한데, release에서 크래쉬가 발생한다는 걸로 봐선 함수를 잘못된 방법으로 사용하고 있을 가능성이 높다고 생각합니다.
릴리즈에서만 발생하고 debug에서 지우고 디버깅하면 에러가 발생하지 않나요?
또 포인터를 사용하는 부분이기 때문에 꼭 이부분때문이 아니라 다른 부분에서 댕글링 포인터같은 잘못된 포인터 접근때문에 발생하는 문제 일수도 있기 때문에, 이것만 가지고는 뭐라고 할수 없을 듯하네요.
사용하시는 라이브러리의 문서를 참고하시는게 좋을 것 같습니다.
kleinstein의 이미지

equation().high_curvature() 이 함수자체에 아무 문제가 없는건 확실합니다.

그리고 두번째 파라메터를 SPAinterval *& 형으로 받기때문에 이 함수를 잘못된 방법으로 사용할 여지도 별로 없어보입니다.

왜냐하면 함수로서는 그냥 포인터를 넘겨받는게 전부니까요..

그리고 이 부분만 도려내면 release 에서 크래쉬도없이 잘 돌아갑니다.

문제는 이 부분에서만 있다는것도 확실한거죠..

그래서 이 함수가 ** 가 아닌 *& 형태의 파라메터로 받는 피치못할 이유가 뭘까가 궁금해졌습니다.

그리고 혹시 *& 형태이기때문에 단순히 포인터를 전해줘서는 안되고 1번 처럼 미리 인스턴스를 만든다음 그 참조자를 가리키는 포인터를 넘겨야 하나 하고 생각도 해봤던거구요..

그런데 1번 처럼 넘기면 여전히 메모리 릭이 발생합니다.

정말 수수께끼입니다.. 저에게는...

일단 저로서는 우선 *& 파라메터라는것 부터 정확히 이해하고 싶습니다.

이게 정확히 무슨 이유에서 ** 과 차별되는건지..

klyx의 이미지

근본적인 차이는 없습니다. 실제로 컴파일러는 참조자를 포인터로 변환하여 컴파일 하는 것으로 알고 있습니다.
어떤 인자를 함수내에서 조작할때 포인터와 참조자가 가능한데, 반드시 포인터로 받아야 하는 경우는 있어도 반드시 참조자로 받아야 하는 이유는 없습니다.
그러므로 여기서 **가 아니라 *&로 받는 이유는 라이브러리를 만든사람이 이쪽이 쓰기 편하다고 생각했기 때문일 것입니다.
또 위에도 적었지만 언제 포인터를 쓰고 언제 참조자를 쓰느냐는 정해진 기준이 없고 어떤 사람은 구별없이 섞어쓰기도, 어떤 사람은 나름 규칙을 정해서 섞어쓰기도 합니다. 이에 대한 논의도 kldp에 몇번 올라왔던 걸로 기억합니다.

그리고 자꾸 *&가 특별한 형태인것처럼 말씀하시는 느낌이 드는데요, 포인터에 대한 참조자는 전혀 특별한 형태가 아닙니다. &는 어떤 형에도 붙을 수 있고 그게 이경우는 포인터가 되었을 뿐입니다.

kleinstein의 이미지

일단 ** 과 *& 의 차이가 없다는게 명확해진 셈이군요.

doldori의 이미지

Quote:

equation().high_curvature() 이 함수자체에 아무 문제가 없는건 확실합니다.

그리고 두번째 파라메터를 SPAinterval *& 형으로 받기때문에 이 함수를 잘못된 방법으로 사용할 여지도 별로 없어보입니다.

왜냐하면 함수로서는 그냥 포인터를 넘겨받는게 전부니까요..

그리고 이 부분만 도려내면 release 에서 크래쉬도없이 잘 돌아갑니다.

문제는 이 부분에서만 있다는것도 확실한거죠..


그건 장담하지 못합니다. 알 수 있는 것은 증상이 거기서 나타난다는 것 뿐이예요.
정말로 equation().high_curvature()에 문제가 없다는 것이 확실하다면
어딘가 다른 곳에서 포인터를 잘못 써서 힙이 이미 망가졌을 수도 있어요.
이런 경우가 참 골치아픈 게 코드를 수정하면 또 다른 곳에서 크래쉬가 나거든요.
끈기있게 디버깅하는 수밖에 없습니다.
appler의 이미지

어렵군요..

C++은 레퍼런스와 포인터의 동시선언이라...

-_-;;;하핫...

<------ 시스너쳐 ------> 3가지 미덕 : 게으름(laziness), 조급성(impatience), 자기 과신(hubris)


Creative Commons License
Appler's Think by Appler is licensed under a Creative Commons 저작자표시-비영리-변경금지 2.0 대한민국 License.


laziness, impatience, hubris

不恥下問 - 진정으로 대화를 원하면 겸손하게 모르는 것은 모른다고 말하는 용기가 필요하다.

kleinstein의 이미지

저는 이 문제에 대해 사실 최근까지도 잘 이해가 가지않았습니다만..

이제서야 좀 알게 되어서 여기에도 그 설명을 적어 놓습니다.
먼저 정답부터 적어놓겠습니다.

anyfunction(int *& a);

라는 함수가 있다면.. 그리고 여기서 a 가 리턴값이라면.. 이라는 전제로 시작됩니다.
이럴 경우 call 하는 쪽에서는 int* a = 0; 라고 해 준 다음 anyfunction(a); 로 불러주면 됩니다.

이제 설명입니다.

anyfunction 이라는 함수안에서 주어진 파라메터 a 에 아래와 같이 메모리를 할당할수 있습니다.

anyfunction(int *& a)
{
a= new int[10];
}

만약 anyfunction(int ** a); 와 같이 선언된 경우에는 anyfunction 을 프로그래밍하는 프로그래머 입장에서는 아래와 같이 메모리를 할당해야합니다.

anyfunction(int ** a)
{
*a= new int[10];
}

일단 anyfunction 을 프로그래밍하는 프로그래머에게는 차이가 좀 있지요.. 일단 첫번째 코드가 읽기가 쉽다는거.
그리고 프로그래밍할때도 더 쉽죠.

*& 냐 혹은 **를 정하는 건 anyfunction을 프로그래밍하는 프로그래머 입장에서 결국 편한쪽으로 선택하는겁니다.

anyfunction 을 호출하는 쪽에서 a 라는 리턴값을 가지고 계속 일을 하게 하려면 anyfunction을 프로그래밍하는 프로그래머 입장에서는 ** 나 *& 둘 중 하나를 선택해야 하는 거죠..
다시한번 말씀드리지만 이렇게 해야만 나중에 anyfunction을 call 한 입장에서 a라는 리턴값으로 계속 일할수 있지요.

만약 anyfunction(int * a); 와 같이 선언된 경우라면

anyfunction(int * a)
{
a= new int[10];
}

이런식으로 a 에 어떤 오브젝트를 Heap 에 만들어서 지정해주는것이 안됩니다.
왜냐하면 anyfunction 을 떠나는 순간 call 하는 입장에서 리턴값을 보면 a 에는 0이 지정되어 있을뿐이거든요.

그래서...
anyfunction 안에서 오브젝트를 만들고 그 포인터를 파라메터 인자로 리턴하고 싶을때 *& 혹은 ** 둘 중 하나를 선택해야 하고..
보통 이런경우 프로그래머입장에서는 *& 형식이 프로그래밍할때 편하기 때문에 *& 형식을 선택하게 됩니다.

물론 anyfunction을 call 하는 입장에서는 나중에 a에 할당된것을 delete나 delete[] 로 직접 지워줘야 겠지요.
누가 지울것인가는 anyfunction을 프로그래밍하는 프로그래머가 가르쳐줘야 합니다.

이제 이 문제가 좀 분명해졌네요.. 누군가 이 글을 보시는 분에게도 도움이 되시길..

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.