C++에서 STL을 함수의 인자나 리턴값으로 쓸때...

ixevexi의 이미지

저는 거의 프로그램을 막시작한 쌩초보라고 할 수 있습니다
그와중에 STL을 한번 배워보고자 맘을 먹었습니다.

그런데 STL의 기능을 잘 설명해둔 책들은 있지만
실제로 어떻게 코드를 짜야하는지 알려주는 책들은 없더군요 -_-;;

앞은 잡소리였고 제가 궁금한것은 다음과 같은 것입니다.


list<int> coll;

//coll에 실컷 멤버들을 넣어두고 요리를 잘 했습니다.
//그리고 그 함수들의 멤버에 어떤 함수로 가공을 하려 합니다.

coll = do_something(coll);

이때 틀림없이 coll을 받는 do_something함수에서는 엄청난 수의
int 가 복사될 것입니다. 또한 리턴값으로도 엄청난 수가 복사될 것입니다.
뻔히 이 엄청난 오버헤드가 보이는데 어쩌질 못하고 있습니다.

물론 STL스타일을 써라

 
 foreach(coll.begin(),coll.end(),do_something);
 
혹은
 
  do_something(coll.begin(),coll.end());

네..... 저렇게되 할 수 있겠쬬 하지만 foreach에 담기에 do_seomthing
이 가지는 분기문이 너무나 복잡하고 아래와 같이 쓰기엔, 조금 유연성이
떨어지는 상황입니다. 머 중간중간에 coll의 크기를 줄이고 늘린달지...
//제가 멍청해서인지는 몰라도 저걸 쓰려니 답답해서요
완전한 coll을 가지고 작업을 하고 싶은 마음인지라 -_-;;

이럴땐 어떤해결책이 필요한지요 -_-;

질문은 아직 끝나지 않았습니다. :oops:

STL을 쓰면서 가장 궁금했던 것입니다. 주로 STL의 자료구조들은
value로 멤버들을 채우더라고요.
저같은 경우에 역시 모자란 실력으로 하다보니 한개의 자료를 동시에
두개의 컨테이너가 가지고 있는 상황이 있었습니다.
예를들면 list<int> 와 vector<int>가 서로의 자료를 공유해야했죠
list에서 자료를 고치면 vector의 자료도 영향을 받게 말이죠...

그런데 이게 쉽지 않더군요 결국 한쪽은 포인터를 써서해결했습니다.
아무리 봐도 근데 안좋은 습관같아서요 -_-;;
이떄의 해결책도 알려주시면 감사하겠습니다.

마지막 질문.. ^^
이건 아주 초보적인건데요

class dumb
{
 private
 list<int> dumber;
};


여기서 dumber의 멤버들은 private이 당연히 아니겠죠?

초보의 질문을 끝까지 봐주셔서 감사드립니다. ^^

pynoos의 이미지

ixevexi wrote:

list<int> coll;

//coll에 실컷 멤버들을 넣어두고 요리를 잘 했습니다.
//그리고 그 함수들의 멤버에 어떤 함수로 가공을 하려 합니다.

coll = do_something(coll);

이때 틀림없이 coll을 받는 do_something함수에서는 엄청난 수의
int 가 복사될 것입니다. 또한 리턴값으로도 엄청난 수가 복사될 것입니다.
뻔히 이 엄청난 오버헤드가 보이는데 어쩌질 못하고 있습니다.

list가 넘어가는 것이 의외로 큰 객체가 넘어갈 것이라 생각하는 경우가 많습니다.
또한 string 도 그 길이만큼 넘어갈 것이라 생각을 하는 경우가 많습니다.
그렇지 않습니다. 확인은 안해봤지만, 16byte도 안될것이라 생각됩니다. 그리고 그 양에 따라 상관없이
항상 같습니다. (물론 구현에 따라 다르지만, 대개의 구현이 그정도입니다.)
reference counting 기법이 적절하게 사용되고 있으며,
멤버함수 끝에 const 가 없는 함수가 사용되는 순간 reference하는 녀석이 자기소유가
아닐경우 복사하는 느린카피가 일어나는 구현이 있습니다.

ixevexi wrote:

이건 아주 초보적인건데요
class dumb
{
 private
 list<int> dumber;
};


여기서 dumber의 멤버들은 private이 당연히 아니겠죠?

초보의 질문을 끝까지 봐주셔서 감사드립니다. ^^

private은 단지 dumber의 접근 가능한 scope을 제한하는 것 뿐이며, 어떤 식으로든 dumber가
넘어 갔다면, 그 안은 접근가능하지요.

ixevexi의 이미지

잘 읽었습니다.
그런데 중간의 질문에는 대답안해주셨어요 ㅜ.ㅜ

중간질문은 두개의 컨테이너가 같은 자료를 공유하려면 어떻게 해야하나 입니다.
/포인터를 빼고/ 한개의 컨태이너를 조작하면 다른 컨태이너의 자료도
영향을 받게끔 말이죠...

그리고 list의 복사말인데요-_-
제가 만드려는 list는 1800자의 한자가 들어있는
상용한자사전정도 입니다.

string의 레퍼런스 카운팅기능이 잘 살아 있어줄까요?
게다가 제가 임의로 구현한 클래스의 경우에는
제가 레퍼런스카운팅 기능을 구현하기도 힘들고, 또 레퍼런트 카운팅
기능의 클래스를 상속해서 쓴다고 하더라도 역시 제 능력을 벗어나게 될듯해서요.

게다가 이번 경우는 coll을 끊임없이 프로그램중간에 고쳐야하는 가혹한
짓을 할껍니다.

저런 경우를 다시 한번 살펴봐주세요. ^^

C++, 그리고 C++....
죽어도 C++

오장현의 이미지

아래처럼 do_something에서 인자를 받을때 컨테이너의 레퍼런스를 받으면 되지 않을까요?
그럼, 복사도 일어나지 않을테고 반환을 할 필요도 없겠죠.

void do_something(list<int> &listColl)
{
    // Do Something
}

void main()
{
    list<int> coll;

    do_something(coll);
}
saxboy의 이미지

Quote:
STL을 쓰면서 가장 궁금했던 것입니다. 주로 STL의 자료구조들은
value로 멤버들을 채우더라고요.
저같은 경우에 역시 모자란 실력으로 하다보니 한개의 자료를 동시에
두개의 컨테이너가 가지고 있는 상황이 있었습니다.
예를들면 list<int> 와 vector<int>가 서로의 자료를 공유해야했죠
list에서 자료를 고치면 vector의 자료도 영향을 받게 말이죠...

그런데 이게 쉽지 않더군요 결국 한쪽은 포인터를 써서해결했습니다.
아무리 봐도 근데 안좋은 습관같아서요 -_-;;
이떄의 해결책도 알려주시면 감사하겠습니다.

저라면 random access가 가능한 container하나를 pool로 사용해서 전부 그 안에 풀링시켜놓고, vector와 list가 풀링된 오브젝트(?)에 대한 포인터를 가지는 식으로 하겠습니다. 그런데, list<int>와 vector<int>가 동시에 이렇게 사용되어야 하는 경우가 어떤 경우인지 무척 궁금해지는군요. 이런 경우는 가능하면 만들지 말아야겠지요.

clhitter의 이미지

ixevexi wrote:

중간질문은 두개의 컨테이너가 같은 자료를 공유하려면 어떻게 해야하나 입니다.
/포인터를 빼고/ 한개의 컨태이너를 조작하면 다른 컨태이너의 자료도
영향을 받게끔 말이죠...

boost의 shared_ptr이라는 reference counting smart pointer를 써보세요. (www.boost.org 참조) 생각보다 사용하기 훨씬 쉽고 또 shared_ptr만 사용하는데는 header 파일만 필요하기 때문에 따로 라이브러리를 링킹한다 던가 하는 것도 필요 없습니다.

ixevexi wrote:

그리고 list의 복사말인데요-_-
제가 만드려는 list는 1800자의 한자가 들어있는
상용한자사전정도 입니다.

string의 레퍼런스 카운팅기능이 잘 살아 있어줄까요?
게다가 제가 임의로 구현한 클래스의 경우에는
제가 레퍼런스카운팅 기능을 구현하기도 힘들고, 또 레퍼런트 카운팅
기능의 클래스를 상속해서 쓴다고 하더라도 역시 제 능력을 벗어나게 될듯해서요.

list가 reference counting을 사용한 구현이 있는지는 잘 모르겠구요, 있다고 하더라도 이렇게 container를 value copy 해야 하는 경우 꼭 list를 쓸 이유가 없으시다면 vector를 쓰시는게 좀 더 performance 면에서 좋습니다.
vector는 continuous 한 memory block들에 element들이 들어가는 것이 보장되기 때문에 한번의 memcpy로 복사가 되지만 list는 그렇지 않기 때문에 n개의 element + link pointer 개수 만큼 복사가 일어나게 될 거거든요

그리고 c++ standard library의 string이 꼭 reference counting을 한다는 것이 보장되어 있는 것은 아닙니다. 그것은 구현하기 나름이구요 실제로 stlport였는지 vc7점대에 포함되어 있는 stl이었는지 잘 모르겠지만 둘 중 하나의 경우 reference counting으로 구현했을 때의 모종의 문제 (이것도 잘 기억이 안나는 군요. 자세히 아시는 분은 답글 부탁드립니다 ^^)로 인해서 reference counting 을 안 하는 것으로 알고 있습니다.

오장현 wrote:

아래처럼 do_something에서 인자를 받을때 컨테이너의 레퍼런스를 받으면 되지 않을까요?
그럼, 복사도 일어나지 않을테고 반환을 할 필요도 없겠죠.

제 생각에도 이것이 정답 아닐까 싶습니다.

ixevexi의 이미지

역시 &로 받는 방법이 와따군요 ^^

그렇게 해볼까 했지만 가능할까하는 의문이 생겼는데....

정말 너무 감사드립니다.

아 그리고 언제 두개의 컨테이너가 필요하냐면,

제가 만드는 프로그램은 문제은행이 있고, 그 중에서 범위/예를 들자면
중간고사랄지/를 정해서 새로운 문제리스트를 갱신하고
거기서 문제를 뽑는 방식을 만든적이 있습니다.

또 전에는 하나는 스택에 넣어두고 하나는 벡터에 넣어둔적이 있습니다.
^^ 이건 약간의 정렬에 관련됨 문제였는데 나중에 처음에 맞춰둔 동적인 인덱스(벡터)가
필요한 시점이 있어서 그랬습니다.

share_ptr, 스마트 포인트계일인듯 하네요 ^^ 좀더 공부해 본후
써보겠습니다. 답변 감사드립니다.

C++, 그리고 C++....
죽어도 C++

voider의 이미지

pynoos님이 deep copy가 일어나지 않는다고 말씀하셨는데...
저는 수긍이 가지 않네요...
stl은 값 을 사용하는 프로그래밍입니다.
그래서 복사를 시키면 정말 복사를 하지 그것을 가지고 레퍼런스 카운팅을 한다거나 그런일을 하지 않을것이라 생각이드는데....

레퍼런스를 사용하면 간단한일을 복사하는데 레퍼런스 카운팅을 하고 하는것은 제가 만들었다고 해도 만들려 하지 않았을 것이라 생각되네요.

단순한것이 가장 아름다운것

-- 아쉬운 하루 되세요 --

pynoos의 이미지

음.. 지금 확인해보니, gcc 2.95.3 과 동반해서 딸려오는 stl 의 string class 는 reference counting 을 합니다만, 다른 container 들은 그렇지 않군요!

pynoos의 이미지

원질문 답변자에게 할말을 별로 못했군요 :)

Container가 인자나 return 값으로 주고받을 때, 복사생성을 시킬것이냐 Reference나 Pointer를 넘길것이냐의 문제는, 사뭇명확합니다.

저의 경우는, 그 함수에서 생성되어 나오는 return 값으로서의 container외에는 복사생성을 하지 않습니다.
또한, 그런일은 별로 없었지만, 그 함수에 넘겨주고 더이상 그 container를 사용하지 않을 때 외에는 복사생성해서 넘기지 않습니다.

그리고, referece 로 넘길때도, 그 함수가 내용을 참고만하는 경우는 const & 로 넘기며, 그 안에서는 const_iterator 를 사용하여 접근합니다.
만약 그 container가 멤버변수이고, 함수가 멤버함수라면, 또한 멤버함수가 그 container 내용을 변경시키지 않는다면,
항상 const 를 선언뒤에 놓고,
(class XXX { void check_data( long d) const; }; )

내부에서는 const_iterator 를 사용하여 scan 합니다.

그리고, 제가 stlport나 VC의 STL 면밀히 보질않아서, 일반화의 오류에 빠졌던것 같습니다.. 양해하시길 바랍니다.. 8)

gcc 2.95에 딸려오는 string class의 reference couting 기법과 소유권을 통해 접근하는 방법은 상당히 재밌는 내용이 많습니다. 그 기법은 glibc의 malloc/free에서 사용하는 것과 유사한 trick이 들어 있습니다.

댓글 달기

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