C++의 perfect forwarding에 관해서 글을 읽던중에 이해가 가지 않아서요~

greathero의 이미지

지금 보고 있는 글의 일부를 잠시 발췌해왔습니다.
발췌시 제약사항은 없어서 괜찮을 것 같구요.
글을 한번 봐주세요.

이동 시맨틱과는 별개로 r-value 레퍼런스는 완벽한 전달(perfect forwarding) 문제를 해결하기 위해서 만들어졌습니다. 아래와 같은 간단한 팩토리 함수를 생각해 봅시다.
 
template<typename T, typename Arg>
shared_ptr<T> factory(Arg arg)
{
  return shared_ptr<T>(new T(arg));
}
 
보시다시피 이 예제의 의도는 팩토리 함수의 인수로 주어진 arg를 T의 생성자로 전달하는 것입니다.
arg의 입장에서 보면 마치 팩토리 함수가 존재하지 않았고 생성자를 상위에서 직접 호출한 것처럼 행동하는 것이 이상적이겠죠. 
이것이 완벽한 전달입니다. 

위의 글에서
이것이 완벽한 전달입니다.> 라는 부분이 해석이 되질 않네요.
이 문장이 무슨 뜻인지를 모르겠어요. "생성자를 상위에서 직접 호출한 것처럼" 이라는 부분이 특히나 와닿질 않네요.

이해하신 분 있으시면 댓글로 풀어서 설명해주시면 정말 감사할 듯 합니다~
아니면 좀 더 쉽게 perfect forwarding에 대해 말씀해 주실 수 있는 분이 있으면 설명 좀 부탁드려요~

kukyakya의 이미지

다음과 같은 클래스가 있다고 가정합니다.

struct value {
  value(const int&) { std::cout << "l-val ctor" << std::endl; }
  value(int&&) { std::cout << "r-val ctor" << std::endl; }
};

그럼 다음과 같이 수행했을 때, l-value reference 생성자와 r-value reference 생성자가 바르게 호출됨을 확인할 수 있습니다.

int main()
{
  int a;
 
  value v1(a);
  value v2(0);
}

이 경우 std::shared_ptr를 생성하는 함수를 만든다고 할 때, 다음과 같은 함수만을 이용했을 시에는 r-value reference생성자가 정상적으로 호출되지 않습니다.

std::shared_ptr<value> make(const int& __v) {
  return std::shared_ptr<value>(new value(__v));
}

따라서 다음과 같이 r-value reference를 인자로 받는 make 함수를 오버로딩해주어야합니다.

std::shared_ptr<value> make(int&& __v) {
  return std::shared_ptr<value>(new value(std::move(__v)));
}

위에서 정의한 value 클래스는 인자를 1개만 받도록 되어있지만, 만약 인자를 2개 이상 받게 된다면 각각의 인자에 대해 l-value, r-value reference의 모든 조합에 대해 make함수를 오버로딩해주어야합니다.

perfect forwarding을 이용하면 make 함수의 인자를 value 생성자로 직접적으로 전달할 수 있게 됩니다.

template <typename T>
std::shared_ptr<value> make(T&& __v) {
  return std::shared_ptr<value>(new value(std::forward<T>(__v)));
}

다음과 같은 코드를 통해 실제로 올바른 생성자가 선택되어 호출됨을 확인할 수 있습니다.

$ cat test.cpp
#include <iostream>
#include <memory>
 
struct value {
  value(const int&) { std::cout << "l-val ctor" << std::endl; }
  value(int&&) { std::cout << "r-val ctor" << std::endl; }
};
 
template <typename T>
std::shared_ptr<value> make(T&& __v) {
  return std::shared_ptr<value>(new value(std::forward<T>(__v)));
}
 
int main()
{
  int a;
 
  auto v1 = make(a);
  auto v2 = make(3);
}
$ gcc -Wall -Wextra -std=c++11 -pedantic -Ofast a.cpp
$ ./a.out
l-val ctor
r-val ctor
greathero의 이미지

깔끔한 소스와 명쾌한 설명 감사합니다 ㅎㅎㅎㅎ

댓글 달기

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