2016-09-15 14 views
11

Tôi đang cố tránh các đối số đầu ra trong các chức năng của mình. Chức năng cũ là:Chức năng trả về một bộ dữ liệu làm bằng vectơ

void getAllBlockMeanError(
    const vector<int> &vec, vector<int> &fact, vector<int> &mean, vector<int> &err) 

Đây vec được tranh luận đầu vào, fact, meanerr là tranh luận đầu ra. Tôi cố gắng để tranh luận đầu ra nhóm để một tuple:

tuple< vector<int>, vector<int>, vector<int> > 
            getAllBlockMeanErrorTuple(const vector<int> &vec) 
{ 
    vector<int> fact, mean, err; 
    //.... 
    return make_tuple(fact, mean, err); 
} 

Bây giờ tôi có thể gọi hàm mới với:

tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec); 

Có vẻ sạch hơn đối với tôi. Trong khi tôi có câu hỏi, việc phân công ngang nhau của tie(fact, mean, err) hoạt động như thế nào? Liệu nó làm một bản sao sâu hoặc di chuyển? Vì fact, meanerr bên trong getAllBlockMeanErrorTuple sẽ bị hủy, tôi hy vọng nó đang di chuyển thay vì bản sao sâu.

+0

Tôi không tích cực, nhưng tôi nghĩ là viết nó sẽ sao chép các vectơ. Nếu bạn di chuyển vectơ vào 'make_tuple()', thì chúng sẽ được di chuyển. – Andy

+5

Tôi sẽ sử dụng kết quả 'struct Result {vector ; vector có nghĩa là; vector err; }; 'thay vì tuple để có tên tốt hơn cho getter. – Jarod42

Trả lời

12

Bạn chức năng chữ ký là tuple< vector<int>, vector<int>, vector<int> >, mà là một tạm thời và các yếu tố có đủ điều kiện để được di chuyển, vì vậy

std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec) 

nên di chuyển-giao fact, meanerr.

Dưới đây là một chương trình mẫu để bạn có thể xem cho chính mình (demo):

#include <iostream> 
#include <vector> 
#include <tuple> 

struct A 
{ 
    A() = default; 
    ~A() = default; 
    A(const A&) 
    { 
     std::cout << "Copy ctor\n"; 
    } 
    A(A&&) 
    { 
     std::cout << "Move ctor\n"; 
    } 
    A& operator=(const A&) 
    { 
     std::cout << "Copy assign\n"; 
     return *this; 
    } 
    A& operator=(A&&) 
    { 
     std::cout << "Move assign\n"; 
     return *this; 
    } 
}; 

std::tuple<A, A> DoTheThing() 
{ 
    A first; 
    A second; 
    return std::make_tuple(first, second); 
} 

int main() 
{ 
    A first; 
    A second; 
    std::tie(first, second) = DoTheThing(); 
} 

Output:

Sao chép ctor
Sao chép ctor
Move gán
Move gán

Lưu ý rằng chức năng phải tạo bản sao của vectơ để trả về tuple, có thể không phải là những gì bạn muốn. Bạn có thể muốn std::move các yếu tố vào std::make_tuple:

return make_tuple(std::move(fact), std::move(mean), std::move(err)); 

Here's the same example as above, but with std::move used in make_tuple

Lưu ý rằng với Bindings cấu trúc C++ 17, bạn có thể quên về việc sử dụng std::tie ở tất cả, và nghiêng thêm về auto (Cảm ơn, @ Yakk):

auto[fact, mean, err] = getAllBlockMeanErrorTuple(vec); 

việc triển khai sớm các tiêu chuẩn C++ 17 cho vang (3.8.0) và gcc (6.1.0) không hỗ trợ nó chưa, tuy nhiên có vẻ như có một số hỗ trợ trong c lang 4.0.0: Demo (Cảm ơn, @Revolver_Ocelot)

Bạn sẽ nhận thấy rằng sản lượng với cam kết ràng buộc thay đổi cấu trúc để:

Move ctor
Move ctor

chỉ ra rằng họ tận dụng lợi thế của sao chép-elision, giúp tiết kiệm các hoạt động di chuyển bổ sung.

+1

'auto [fact, mean, err] = getAllBlockMeanErrorTuple (vec);' – Yakk

+1

@Yakk: Không phải là C++ 17 sao? – AndyG

+0

Có, nhưng tôi sẽ tranh luận đáng nói đến, ít nhất là khi đi qua. – Yakk

11
std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec); 

sẽ thực hiện chuyển nhượng.

Nhưng như đã đề cập trong bình luận

return make_tuple(fact, mean, err); 

sẽ làm một bản sao, bạn có thể giải quyết điều đó với:

return make_tuple(std::move(fact), std::move(mean), std::move(err)); 
+0

Ít nhất đề cập đến C++ 17 ràng buộc có cấu trúc! Chúng tôi chỉ còn vài tháng nữa thôi. (đối với các giá trị giới hạn ở đây) – Yakk

+0

Cảm ơn bạn Jarod42. –

Các vấn đề liên quan