2017-12-10 2 views
2

나는이 두 가지 간단한 기능을 가지고 있습니다. 나는 func1이 객체를 참조로 전달 했으므로 좋은 해결책이라고 생각했습니다. 내 교과서는 최상의 솔루션에 대한 답변으로 func2을 부여했습니다. 이것은 heapstr의 할당을 해제하지 않았기 때문입니까? 주에서 heapstr을 선언하고 함수에 전달하면 나중에 삭제할 수 있습니까? 이 교과서 예제이기 때문에힙 객체 또는 반환 값에 대한 참조를 반환해야합니까?

#include <iostream> 

using namespace std; 


string& func1(const string &str) { 
    string* heapstr=new string(); 
    for (int i = 0; i < str.size(); ++i) { 
     *heapstr += str[i]; 
    } 
    return *heapstr; 
} 

string func2(const string &str) { 
    string heapstr; 
    for (int i = 0; i < str.size(); ++i) { 
     heapstr += str[i]; 
    } 
    return heapstr; 
} 

int main() { 
    cout << func1("aaa") << endl; 
    cout << func2("aaa") << endl; 
} 
+2

가치! 항상 기본값으로 값을 선호합니다! 그 누출에 대해서 이야기조차하지 않고 있습니다. – StoryTeller

+0

'func2', 더 안전하고 빠름 (https://stackoverflow.com/questions/161053/which-is-faster-stack-allocation-or-heap-allocation) – macroland

+0

일반 포인터를 사용하려면 다시 생각해보십시오. 그렇게할만한 이유가 있다면 – Simon

답변

5

힙 개체 또는 반환 값에 대한 참조를 반환해야합니까?

반환 값.

컴파일러가 작업을 최적화하는 데 충분하고 성능이 좋지 않은 경우에도 대부분의 프로그램은 I/O 바인딩, 즉 파일이나 네트워크 소켓에서 데이터를 기다리는 시간은 CPU 작동에 소요되는 시간이 아니라 모든 성능을 향상시킵니다.

예를 들어 절을 참조 "Return containers by value (relying on move or copy elision for efficiency)"에서 말하는 허브 셔터와 비얀 스트로브 스트 룹으로 "C++ 핵심 가이드 라인", : 코드를 단순화하고 명시 적 메모리 관리에 대한 필요성을 제거하기 위해

이유

. 당신의 두 가지 기능에 관해서는

...

내 교과서는 최적의 솔루션에 대한 답변으로 func2했다.이것은 heapstr의 할당을 해제하지 않았기 때문입니까?

메모리 누수가 문제 중 하나입니다. 그러나 요점은 값으로 돌아 오는 것이 더 간단하고 오류가 발생하기 쉽다는 것입니다. 모든 것이 정확도이지 속도가 아닙니다. 대신 int을 반환 할 수 있다면 int*을 반환하지 않겠습니까? 내가 main에서 heapstr를 선언하고 함수에 전달하면 어떻게

그래서 나중에 그것을 제거 할 수 있었다?

코드에 메모리 누수, 충돌 및 정의되지 않은 동작에 대해 많은 가능성을 소개합니다. 코드 리뷰에서 더 길어지고, 작성하기가 더 어려워지고, 읽기가 어렵고, 유지 관리가 어려우며, 디버그하기가 어려워지고 정당화하기가 어려울 것입니다. 그 대가로 당신은 절대 아무것도 얻지 못할 것입니다.

+0

당신 같은 사람들이 내 것보다 더 나은 답을 쓰는 것을 계속한다면 어떻게 10,000 회에 도달 할 수 있습니까? –

1

, 당신은 (그것의 목표는 같은 메모리 사용을 최소화하거나 안전한 프로그래밍 패턴을?! 사용하는 것입니다) 정확히 보여주고 싶은 것을 underestand하기 위해 문맥을 고려해야한다. 그러나 두 사람은 힌트

  1. 메모리를 할당 할 new 연산자를 사용

    , 당신은 delete를 사용하여 드 할당해야합니다. 코드는 heapstr에 대한 메모리 누수가 func1입니다.
  2. 또한보다 현실적인 프로젝트에서는 메서드간에 개체를 공유하는 것이 안전하지 않습니다. 관리 (즉, 현재 수정 된 사람 또는 객체가 더 이상 필요하지 않을 때 메모리를 할당 취소 할 책임이있는 사람)는 어려워졌습니다.

추신 : 저는 C++ 17이 없지만 다음과 같이 최적화됩니다. 자세한 내용은 @BoPersson 주석을 참조하십시오.

추 신 : 스택 할당은 빠르지 만, 예에서 func2 return시 복사 작업이 있습니다. (@Jive Dadson, 당신의 예에서 차이가 없다고 말했다 그러나 : @Jive Dadson 같은 예에서

#include <iostream> 
#include <string> 
using namespace std; 


string& func1(const string &str) { 
    string* heapstr = new string(); 
    cout << "func1 " << heapstr << endl; 
    for (int i = 0; i < str.size(); ++i) { 
     *heapstr += str[i]; 
    } 
    return *heapstr; 
} 

string func2(const string &str) { 
    string heapstr; 
    for (int i = 0; i < str.size(); ++i) { 
     heapstr += str[i]; 
    } 
    cout << &heapstr << endl; 
    return heapstr; 
} 

int main() { 
    string a = func1("aaa"); 
    string b = func2("aaa"); 
    cout << "main " << a << endl; 
} 

PS이 차이로 인해 해주 컴파일러 최적화가 없지만 일반적인 경우에, 코드를 다음과 같은 가정했다 in mine) 성능을 런타임으로 정의하면 func1 일 수 있습니다. 또한 성능을 메모리 사용량으로 정의하면 func1. 퍼포먼스를 좋은 프로그래밍 패턴으로 정의한다면, func2. 완전히 func2가 더 선호됩니다.

+0

func1에는 힙에 포인터와 문자열이 있습니다. func2에는 문자열 만 있습니다. 그것은 * less * 메모리입니다. 이미 대부분의 컴파일러는 func2의 반환 값을 복사하지 않고'b'에 직접 만듭니다. C++에서이 복사 제거는 이제 필수입니다. –

+0

@BoPersson _... 이미 대부분의 컴파일러 ... _ 나는 C++ 17이 대부분의 컴파일러로서 그것을 셀 수 있다고 생각합니다. VS17 (11 이상 사용)으로 확인합니다. 첫 번째 부분에 대해서는 컴파일러가 최적화한다고 가정하면 적절합니다. 또한 메모에 감사드립니다. 내 대답을 업데이트합니다. –

+0

복사 elision은 항상 허용되었으므로 종종 작동합니다. g ++ 및 clang의 최신 릴리즈는 이미 C++ 17을 구현했으며 VS2017은 [버전 15.6의 미리보기] (https://www.visualstudio.com/en-us/news/releasenotes/vs2017-html)에서 구현 된 복사 제거를 방금 받았습니다. 미리보기 - 잔주름). –

2

텍스트 북이 정확합니다. (Shocker.)

func1은 func2와 다른 점에서 모두 결함이 있습니다. 이 개체를 삭제하는 방법에 관계없이 힙에서 개체를 할당합니다. 그런 다음 새 객체에 대한 참조를 반환하고 포인터를 삭제하여 포인터를 삭제합니다. 사실 Func1은 아마도 약간 느릴 것입니다. 어쨌든, 나에게 암송하십시오 : "조기 최적화를 피하십시오."

표준 템플릿 라이브러리가 등장한 이래 많은 달 전부터 new 연산자를 사용하는 것이 거의 절대적이지 않습니다. 내가 new 연산자를 사용한 마지막 시간은 ca였습니다. 2003, 그리고 우리가 지금 unique_ptr로 알고있는 것에 상응하는 포인터를 감쌌다. new 연산자를 사용하기 전에 스마트 포인터와 RAII에 대해 모두 배우십시오.

관련 문제