2017-12-10 8 views
2

에 일시적으로 수정 된 벡터를 통과, 나는 벡터는 각 레벨에서 수정되는 방식으로 함수에 벡터를 통과해야하고 관계없는 코드.되돌아 문제에서 함수

나중에 벡터 수정을 단순화하여 나중에 pop_back 할 필요가없는 방법이 있습니까?

+0

연산자 []를 통해 벡터를 수정 하시겠습니까? –

+0

각 호출에서 전체 벡터를 복사 하시겠습니까? – Yakk

+0

@Yakk 메모리 처리가 문제가 발생하는 재귀 수준에서 문제가되지 않기 때문에 값으로 전달하는 것이 컴파일러 최적화로 인해 더 빠를 수 있다고 읽었습니다. – byrass

답변

1

내가 무엇을해야하는 것은 이미 꽤 읽을는 사실을 알게 될 것입니다. 개선 할 점은 두 가지뿐입니다.

우선, 중복 복사본을 피하고 참조로 벡터를 전달하십시오.

둘째, 백 트랙킹 불변성을 유지하려면 여전히 pop_back을 유지해야합니다. 하지만 당신은 덜 어색 장소로 이동할 수 있습니다 : 함수가 튀어

void function(std::vector<int> &vec){ 
    vec.push_back(0); // Initial modification 
    function(vec); 
    vec.back() = 1; // Second modification 
    function(vec); 
    vec.pop_back(); // Return to previous state 
    return; 
} 

때문에 매우 그것을, 우리는 vec.back() 통화 사이의 정수는 것을 확신 할 수 있습니다 밀어 정수. 따라서 팝과 푸시의 다른 쌍 대신 간단한 할당을 할 수 있습니다.

+0

매번 동일한 벡터로 푸시하고 팝을하려면 함수 인수로 참조를 사용하거나 벡터 변수를 전역으로 정의하는 것이 좋습니다. 이 방법으로, 당신은 많은 기억을 낭비합니다. – Alireza

+0

이 답변은 팝백이 무의미하다는 점을 제외하고는 예외가 아닙니다. – Yakk

+0

@Yakk - 무엇을 던지 느냐에 달려 있습니다. 그것이 단지 벡터라면, RAII popper는 가미 카제의 헬멧입니다. – StoryTeller

3

당신은 파괴에 당신을 위해 자동으로 pop_back를 호출하는 가드 클래스를 만들 수 있습니다

template <typename T> 
class push_pop_guard 
{ 
private: 
    std::vector<T>& _v; 

public: 
    template <typename Item> 
    push_pop_guard(std::vector<T>& v, Item&& x) : _v{v} 
    { 
     _v.push_back(std::forward<Item>(x)); 
    } 

    ~push_pop_guard() 
    { 
     _v.pop_back(); 
    } 
}; 

사용 예 :

void function(std::vector <int> vec) 
{ 
    { 
     push_pop_guard ppg{vec, 0}; 
     function(vec); 
    } 

    // ... 
} 
+0

While (매우) 차가운, 이것은 무언가에 간단한 불필요한 복잡성을 추가합니다. –

+0

T를 떨어 뜨리고 컨테이너에 C를 추가합니다. C가 추론 될 수 있도록 팩토리 함수를 작성하고이를'auto'로 저장하십시오. – Yakk

+0

왜 downvote? –

2

당신은 방법에 값을 전달하고 나중에 벡터에 밀어 수 있습니다

void function(std::vector <int> vec, int element){ 
    vec.push_back(element); 
    //Do stuff 
    function(vec,0); 
    function(vec,1); 

    return; 
} 
+1

아주 좋습니다! 프로토 타입을 디폴트 값으로'int element = 0'으로 만들 수 있습니다. –

1
template<class F> 
struct scope_guard_t { 
    std::optional<F> f; 
    scope_guard_t(F in):f(std::move(f)) {} 
    scope_guard_t(scope_guard_t&& o): 
    f(std::move(o.f)) 
    { 
    o.clear(); 
    } 
    void abandon() { clear(); } 
    void commit_early() { commit(); clear(); } 
    ~scope_guard_t() { commit(); } 
private: 
    void commit() { if(f) (*f)(); } 
    void clear() { f = std::nullopt; } 
}; 
template<class F> 
scope_guard_t<F> scope_guard(F in) { return {std::move(in)}; } 

template<class C, class T> 
auto temp_push(C& c, T&& t) { 
    c.push_back(std::forward<T>(t)); // do 
    return scope_guard(
    [&]{ c.pop_back(); } // undo 
); 
} 
void function(std::vector <int> vec){ 
    { 
    auto scope = temp_push(vec, 0); 
    function(vec); 
    } 

    { 
    auto scope = temp_push(vec, 1); 
    function(vec); 
    } 
} 

std::optional 및 이전에 boost::optional로 대체 할 수 있습니다.

scope_guard이 일반적으로 유용합니다.

나는 또한 참조로 전달하여 값으로 전달되는 vector을 대체합니다. 훨씬 더 효율적일 수 있습니다. 각 재귀마다 재 할당을 피할 수 있습니다.