2012-03-02 3 views
2

수학적 의미에서 매핑을 나타내는 몇 가지 클래스, 즉 f : RxR^n -> R^n을 구현합니다. 나는 하나의 추상 기본 클래스를 구현하고 싶다 : 1) 참조로 std :: array를 가져 와서 또는 2) std :: array를 반환한다. (값 또는 참조에 의해 확실하지 않은가?)std :: array를 반환합니다.

옵션 2의 구문은 코드가 더 많이 표현하려고하는 것처럼 보이기 때문에 더 바람직합니다.하지만 불필요하게 물건을 복사하고 원하지 않는 것을 유도하고 싶습니다. 간접비. 예를 들어 내가이 있다면 :

// Function f declaration 
std::array<double, 4> f(double t, const std::array<double, 4> & x); 

// Some code snippet that uses f 
std::array<double, 4> x = {0.0, 1.0, 2.0, 3.0}; 
double t = 0.0; 
std::array<double, 4> dxdt = f(t, x); 
내가 복사본을 마지막 줄에 수행되고 있는지 여부를 확인할 수 있습니다, 또는 나는 그것이 이 발생하지 않는다는 것을 어떻게 보장 할 수 있습니까

?

f()의 정의 내에서 복사 생성자를 호출하지 않고 이것이 반환되도록하려면 무엇이 필요합니까? 클라이언트가 포인터 나 스마트 포인터를 사용할 필요가 없도록 간단하게 사용하고 싶습니다만, 이것이 필요한 것일 수 있습니까?

void를 반환하도록 변경할 수 있으며 인수 중 하나를 std :: array dxdt로 지정해야하지만 성능 저하 또는 메모리 누수 문제가없는 한 반환 값 구문이 더 좋습니다.

답변

8

복사 최적화는 컴파일러 문제이기 때문에주의해서는 안되는 내용이어야합니다. 그러나 컴파일러는 최적화 자체를 발명 할 수없는 Turing 기반의 기계입니다.

  • 하나의 return 문 또는 ...이
  • 가 모두 같은 변수

를 반환 여러 반환이 있습니다

는 지금까지 오늘의 컴파일러의 대부분은 함수가있는 경우, 행동 알고 컴파일러는 함수 호출이 속한 표현식에 의해 평가되어야하는 위치에서 스택에 해당 변수를 할당합니다. 해당 복사본이 생성되지 않습니다.

함수에 여러 표현식을 반환하는 exit가 여러 개있는 경우이 특정 사례를 수행 할 수 없습니다.

따라서 일반적으로 와이드 오브젝트를 반환해야하는 경우이를 선언하고 모든 return 문이이를 리턴하는지 확인하십시오.

+0

고마워! 내 함수 호출의 마지막 매개 변수를 "출력"매개 변수로 사용하겠습니다. 왜냐하면 함수 호출이 보유 할 변수를 선언 할 때와 같은 줄에서 발생하지 않을 수 있기 때문입니다 반환 값, 그리고 이런 식으로, 나는 어떤 사본도 만들어지지 않는다는 것을 확실히 알고있다. – hazelnusse

+0

@ hazelnusse : 그렇게 할 수 있다면 반환 값을 "출력 매개 변수"로 지정하면 모든 반환 문이 분명하게 동일한 변수를 반환 할 수 있습니다. 따라서 명명 된 반환 값 최적화가 시작됩니다. 그래서 ... 무엇이 문제입니까? –

+0

@hazelnusse : "... 같은 줄에는 ... 일어나지 않는다" "회선"에 관해서는 이야기하지 않았다. ... 내가 얻지 못한 것이 있는가? –

1

필자는 불필요한 복사에 대해 걱정할 필요가 없다고 생각합니다. 컴파일러는 이러한 것들을 최적화하는 데 꽤 능숙합니다. RVO (Return Value Optimization)를 사용하여 불필요한 사본을 제거 할 수 있습니다. 그리고 C++ 11 지원 컴파일러를 사용하는 경우 move 의미 체계로 인해 복사가 더욱 줄어 듭니다.

+5

'std :: array '의 특별한 경우에, move semantics는 거의 가치가 없다. 이동 의미는 간접 참조 (동적으로 할당 된 메모리 및 포인터)가있을 때만 도움이됩니다. –

0

참조로 돌아 오면 복사 작업이 없습니다 (실제로 우리는 메모리 주소 인 4 바이트 만 처리합니다).

std::array<double, 4> f(double t, const std::array<double, 4> & x); 

...로 전환 될 수있다 : ..

std::array<double, 4>& f(double t, const std::array<double, 4> & x); 

그럼되기 때문에 (리턴 값은 하지 함수 자체 내의 로컬 변수 스택 할당 것을 구비 반환 된 후 매달린 참조).

컴파일러가 자동으로 수행하는 경우가 있지만, 더 명확하게 명시하는 것이 좋습니다. 복사가 발생하지 않도록하고 싶습니다.

+0

Hum ... 그 전역 변수를 참조해야합니다. 별로 좋지 않습니다. –

2

걱정하지 마십시오. 매우 일반적인 사용 사례이며 컴파일러가 잘 이해하고 있습니다. 그래도 최적화를 활성화하십시오. 한 가지 더, 배열의 길이가 4 double이라면, 그 전에 더 중요한 것들을 최적화해야 할 것입니다. 당신이 그것을 필요로한다는 것을 알기도 전에 (즉, 당신이 측정 한) 나쁜 것이라는 것을 알기 전에 최적화를한다는 것을 잊지 마십시오.

이제 실제로 복사본이 없는지 확인하려는 경우 어셈블리 코드를 살펴볼 수 있습니다 (컴파일러/도구에 따라 다름). 또한

당신이 할당 연산자가 호출되지 않습니다 있는지 확인하기 위해 복사 생성자에 뭔가를 인쇄 위치를 자신의 클래스를 쓸 수 있지만, std::array<> 당신이 도출되지 않는 한 그렇게 할 수 없습니다 그것에서 허용되지 않습니다 (그것은 컴파일되고 실행됩니다).

관련 문제