반환형이 포인터의 참조자입니다.

obbaya의 이미지

int*& x();

함수선언이 이렇게 되어 있습니다.

조금 당혹스러운데
함수선언에서 반환형이 무엇을 말하고 있는지 모르겠어요...

반환형이 * 인 것과 *& 인 것의 차이를 아시는 분은 알려주세요.

감사합니다.

obbaya의 이미지

출처는 ios_base::pword 입니다.
void* &pword(int idx);

변수에서 &가 붙으면 바로 초기화를 해야되는 강제 정도의 의미가 있을까 싶은데
반환타입에서는 도통 어떤 의미가 있는 건지 모르겠네요.
역어셈블 코드를 따라가보아도 &가 있든 없든 코드 차이가 안보이고 흠......

sia79의 이미지

컴파일이 안될 것같은데... 역 어셈블 코드를 따라가셨다는 말씀은 컴파일이 되었다는 ...?

obbaya의 이미지

네 g++ 이랑 VC++ 2008에서 컴파일 및 테스트를 해보고 있어요.
ios_base::pword 가 c++ 표준 입출력의 일부이니 문법에 이상이 있다고 볼 순 없을 거 같에요.

yielding의 이미지

int*& 는 int 포인터의 레퍼런스 (int&* 이런 표현은 없습니다.) 그냥 그대로 받아들이면 됩니다.
함수의 인자로 넘길때는 넘긴 포인터가 다른 번지를 가르키게 할때 쓰고(이중 포인터보다 코드가 깔끔해지겠죠)
함수의 리턴타입으로 쓸때는.. **(double pointer)를 리턴하는 경우의 코드를 깔금하게 쓰고싶을때 (^^)
즉, C에서 **를 써야하는 경우 c++에서 *&를 쓰면 코드가 좀 더 깔끔해지는 잇점이 있습니다.

여담으로, 레퍼런스를 리턴하는 경우는 많죠. stack이라는 객체의 push가 stack&를 리턴하면
stack s; s.push(1).push(2).push(3); 이런 expression이 가능하겠죠.

Life rushes on, we are distracted

obbaya의 이미지

yielding님 답변 감사합니다.
말씀처럼 간단한 테스트를 해보았는데

class TestCase {
public:
int*& test()
{
isPossible = new int* [2];
for (int i=0; i < 2; ++i) isPossible[i] = new int[2];
...

return isPossible;
}
private:
int** isPossible;
};

컴파일을 하면 (VC++ 2008)
......'return' : 'int **'에서 'int *&'(으)로 변환할 수 없습니다.
에러가 나네요.
더블 포인터를 리턴하는 경우에 코드를 깜끔하게 쓰고 싶을 때란 말씀과 상충하는게 아닐까요?
제가 테스트를 잘못한 것인지 모르겠지만요.

litdream의 이미지

First of all, sorry for English. My laptop which speaks Korean isn't available today. And I am slacking now :) So I will be quick.
What yielding-nim said was that Using *& in c++ takes advantage of reference. If the same thing should be written in C, double pointer should be involved.

I have made a quick-and-dirty example. Don't expect this to be a perfect one, though.

In C++,

#include <iostream>
#include <string>
using namespace std;
 
class Person {
public:
    Person(const string &);
    string name;
};
 
Person::Person(const string &n) : name(n) {}
 
Person *gPer;
 
Person*& personFactory(const string n) 
{
    extern Person *gPer;
    gPer = new Person(n);
    return gPer;
}
 
int main()
{
    Person *p = personFactory(string("Foo-bar"));
    cout << p->name << endl;
 
    return 0;
}

If we write the same code in C,

include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
struct Person {
    char name[50];
};
 
int createPerson(struct Person **p, const char *name)
{
    *p = malloc(sizeof (struct Person));
    if (!p) 
        return -1;
    strcpy((*p)->name, name);
    return 0;
}
 
int main()
{
    struct Person *p;
    createPerson(&p, "Foo-bar");
    printf("%s\n", p->name);
    return 0;
}

In C++ example, I used extern to denote that this memory block is managed by somebody else. Like application level data structure object.
I hope this makes sense to you.

삽질의 대마왕...

삽질의 대마왕...

obbaya의 이미지

litdream님 답변 감사합니다.
yielding님의 말씀을 제가 제대로 이해를 못했었네요.

그런데 여전히 의문이 들어요.

Person*& personFactory(const string n)

이 라인에서 &가 왜 있는지 모르겠어요. 없어도 결과는 같은데,
무언가 이유가 있으니깐 있는 것일테고... 그 이유를 모르겠습니다.

한번 더 답변 부탁드립니다.
감사합니다.

litdream의 이미지

Okay, I am slacking again. :)
I hope this example clarifies a little further. Still not a perfect one, yet.

#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
 
class Person {
public:
    Person(const string &);
    string name;
};
 
Person::Person(const string &n) : name(n) {}
 
Person *gPer;
 
Person*& personFactory(const string n) 
{
    extern Person *gPer;
    gPer = new Person(n);
    return gPer;
}
 
Person* personFactory2(const string n)
{
    extern Person *gPer;
    gPer = new Person(n);
    return gPer;
}
 
int main()
{
    extern Person *gPer;
    Person *&p = personFactory(string("Foo-bar"));
    cout << p->name << endl;
    printf("%u, %u, %u, %u\n", gPer, p, &gPer, &p);
 
    //I DON'T CARE A MEMORY LEAK HERE!
    Person *p2 = personFactory2(string("Foo-bar"));
    cout << p2->name << endl;
    printf("%u, %u, %u, %u\n", gPer, p2, &gPer, &p2);
 
    return 0;
}

Its running is:

$ ./a.out
Foo-bar
138784800, 138784800, 134517236, 134517236
Foo-bar
138784840, 138784840, 134517236, 3221111428

Note that the third and the forth are in our attention.
First line tells that address of gPer and p are the same, but Second line tells they are different.
These values are the actual VM address in use at CPU registers.

삽질의 대마왕...

삽질의 대마왕...

삽질 대천사의 이미지

고맙습니다. 출력 된 메모리 번지를 보았을 때, 삽을 내려놓을 수 있었습니다.
하지만 아직 삽은 많습니다.

sixmen의 이미지

#include <iostream>
using std::cout;
int g[2] = { 1, 2 };
class A
{
public:
    int *p;
    A() { p = g; }
    int *&getp() { return p; }
};
 
int main()
{
    A a;
    cout << a.getp()[0] << std::endl;
    a.getp()++;
    cout << a.getp()[0] << std::endl;
}

결과를 해보면 1, 2가 나옵니다.

reference로 받는 다는 얘기는 받은 것을 단순히 사용하는 것 뿐 아니라 원래 값에 변형을 줄 수 있다는 얘기가 됩니다.
class A가 갖는 p라는 포인터 변수의 값을 a.getp()++; 로 바꿀 수 있다는 얘기죠.

포인터 증가 부분을

int *&p = a.getp(); p++;

로 쓰면 역시 1, 2가 나오는데

int *p = a.getp(); p++;

로 쓰면 1, 1이 나옵니다.

그리고 getp가

int *getp() { return p; }

라면

a.getp()++; // compile error
int *&p = a.getp(); p++; // compile error
int *p = a.getp(); p++; // ok

입니다. C로는 int ** 로 쓸 걸 int *&로 쓴 거라 이해하실 수도 있고요, 포인터라는 거 신경쓰지 마시고, int *와 int &의 차이를 생각해보시면 감이 오지 않을까 싶습니다.

삽질 대천사의 이미지

두분 덕분에 이해가 확실히 됐네요. 오래전 글이라 보실지 모르지만 두 분 모도 감사합니다.

obbaya의 이미지

sixmen님 답변 감사합니다.

a.getp()++에서 무릎이 탁 쳐지네요.

참조자가 아닌 리턴타입은 리턴시 생성되는 임시객체가 read-only 속성을 가진다.
참조자 리턴타입은 리턴시 생성되는 임시객체가 read-write 속성을 가진다.

전 결론을 이렇게 내렸습니다.
그리고

int*& getp() 이고
int*& rp = getp(); 인 경우에는
getp()의 리턴과 함께 생성된 임시객체를 rp가 포인팅하게 된다.
즉 참조자 임시객체는 임시객체를 포인팅할 수 있는 심볼을 가지게 되면 일반 변수가 될 수 있다.

지금 제 결론이 맞는건지 아니면 또 제가 오해를 하고 있는건지 모르겠네요.

C++의 참조자 메커니즘을 정확히 몰라서 생기는 의문인 것 같은데
고마운 답변을 조금 더 기대합니다.
감사합니다.

lovewar의 이미지

reference type은 parameter passing(인자 전달방식)중 call by reference를 이해하면 됩니다.

  int * p  = new int(20);
  int *& pr = p;
  pr = 0;
  cout << p << std::endl;

함수 반환형으로 reference형을 선언할때는 위 코드의 문제처럼 주의해서 코딩을 해야 합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.