C ++ Tuple vs Struct


96

Có sự khác biệt nào giữa việc sử dụng a std::tuplevà chỉ dữ liệu structkhông?

typedef std::tuple<int, double, bool> foo_t;

struct bar_t {
    int id;
    double value;
    bool dirty;
}

Từ những gì tôi đã tìm thấy trên mạng, tôi thấy rằng có hai điểm khác biệt lớn: cái structdễ đọc hơn, trong khi tuplecó nhiều chức năng chung có thể được sử dụng. Nên có bất kỳ sự khác biệt hiệu suất đáng kể nào không? Ngoài ra, bố cục dữ liệu có tương thích với nhau không (thay thế cho nhau)?


Tôi chỉ nhận xét rằng tôi đã quên về câu hỏi cast : việc triển tuplekhai thực hiện được xác định, do đó nó phụ thuộc vào việc triển khai của bạn. Cá nhân, tôi sẽ không tin tưởng vào nó.
Matthieu M.

Câu trả lời:


32

Chúng tôi có một cuộc thảo luận tương tự về tuple và struct và tôi viết một số điểm chuẩn đơn giản với sự giúp đỡ từ một đồng nghiệp của tôi để xác định sự khác biệt về hiệu suất giữa tuple và struct. Đầu tiên chúng ta bắt đầu với một cấu trúc mặc định và một bộ tuple.

struct StructData {
    int X;
    int Y;
    double Cost;
    std::string Label;

    bool operator==(const StructData &rhs) {
        return std::tie(X,Y,Cost, Label) == std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
    }

    bool operator<(const StructData &rhs) {
        return X < rhs.X || (X == rhs.X && (Y < rhs.Y || (Y == rhs.Y && (Cost < rhs.Cost || (Cost == rhs.Cost && Label < rhs.Label)))));
    }
};

using TupleData = std::tuple<int, int, double, std::string>;

Sau đó, chúng tôi sử dụng Celero để so sánh hiệu suất của cấu trúc và tuple đơn giản của chúng tôi. Dưới đây là mã điểm chuẩn và kết quả hiệu suất được thu thập bằng cách sử dụng gcc-4.9.2 và clang-4.0.0:

std::vector<StructData> test_struct_data(const size_t N) {
    std::vector<StructData> data(N);
    std::transform(data.begin(), data.end(), data.begin(), [N](auto item) {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(0, N);
        item.X = dis(gen);
        item.Y = dis(gen);
        item.Cost = item.X * item.Y;
        item.Label = std::to_string(item.Cost);
        return item;
    });
    return data;
}

std::vector<TupleData> test_tuple_data(const std::vector<StructData> &input) {
    std::vector<TupleData> data(input.size());
    std::transform(input.cbegin(), input.cend(), data.begin(),
                   [](auto item) { return std::tie(item.X, item.Y, item.Cost, item.Label); });
    return data;
}

constexpr int NumberOfSamples = 10;
constexpr int NumberOfIterations = 5;
constexpr size_t N = 1000000;
auto const sdata = test_struct_data(N);
auto const tdata = test_tuple_data(sdata);

CELERO_MAIN

BASELINE(Sort, struct, NumberOfSamples, NumberOfIterations) {
    std::vector<StructData> data(sdata.begin(), sdata.end());
    std::sort(data.begin(), data.end());
    // print(data);

}

BENCHMARK(Sort, tuple, NumberOfSamples, NumberOfIterations) {
    std::vector<TupleData> data(tdata.begin(), tdata.end());
    std::sort(data.begin(), data.end());
    // print(data);
}

Kết quả hiệu suất được thu thập với clang-4.0.0

Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
     Group      |   Experiment    |   Prob. Space   |     Samples     |   Iterations    |    Baseline     |  us/Iteration   | Iterations/sec  | 
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort            | struct          | Null            |              10 |               5 |         1.00000 |    196663.40000 |            5.08 | 
Sort            | tuple           | Null            |              10 |               5 |         0.92471 |    181857.20000 |            5.50 | 
Complete.

Và kết quả hiệu suất được thu thập bằng cách sử dụng gcc-4.9.2

Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
     Group      |   Experiment    |   Prob. Space   |     Samples     |   Iterations    |    Baseline     |  us/Iteration   | Iterations/sec  | 
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort            | struct          | Null            |              10 |               5 |         1.00000 |    219096.00000 |            4.56 | 
Sort            | tuple           | Null            |              10 |               5 |         0.91463 |    200391.80000 |            4.99 | 
Complete.

Từ kết quả trên chúng ta có thể thấy rõ rằng

  • Tuple nhanh hơn cấu trúc mặc định

  • Sản phẩm nhị phân bằng clang có hiệu suất cao hơn của gcc. clang-vs-gcc không phải là mục đích của cuộc thảo luận này nên tôi sẽ không đi sâu vào chi tiết.

Tất cả chúng ta đều biết rằng viết toán tử == hoặc <hoặc> cho mỗi định nghĩa cấu trúc đơn lẻ sẽ là một nhiệm vụ khó khăn và nhiều lỗi. Hãy thay thế bộ so sánh tùy chỉnh của chúng tôi bằng cách sử dụng std :: tie và chạy lại điểm chuẩn của chúng tôi.

bool operator<(const StructData &rhs) {
    return std::tie(X,Y,Cost, Label) < std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
}

Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
     Group      |   Experiment    |   Prob. Space   |     Samples     |   Iterations    |    Baseline     |  us/Iteration   | Iterations/sec  | 
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort            | struct          | Null            |              10 |               5 |         1.00000 |    200508.20000 |            4.99 | 
Sort            | tuple           | Null            |              10 |               5 |         0.90033 |    180523.80000 |            5.54 | 
Complete.

Bây giờ chúng ta có thể thấy rằng việc sử dụng std :: tie làm cho mã của chúng ta thanh lịch hơn và khó mắc lỗi hơn, tuy nhiên, chúng ta sẽ giảm hiệu suất khoảng 1%. Tôi sẽ ở lại với giải pháp std :: tie ngay bây giờ vì tôi cũng nhận được cảnh báo về việc so sánh các số dấu phẩy động với trình so sánh tùy chỉnh.

Cho đến nay chúng tôi vẫn chưa có bất kỳ giải pháp nào để làm cho mã cấu trúc của chúng tôi chạy nhanh hơn. Hãy xem qua hàm hoán đổi và viết lại nó để xem liệu chúng ta có thể đạt được bất kỳ hiệu suất nào không:

struct StructData {
    int X;
    int Y;
    double Cost;
    std::string Label;

    bool operator==(const StructData &rhs) {
        return std::tie(X,Y,Cost, Label) == std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
    }

    void swap(StructData & other)
    {
        std::swap(X, other.X);
        std::swap(Y, other.Y);
        std::swap(Cost, other.Cost);
        std::swap(Label, other.Label);
    }  

    bool operator<(const StructData &rhs) {
        return std::tie(X,Y,Cost, Label) < std::tie(rhs.X, rhs.Y, rhs.Cost, rhs.Label);
    }
};

Kết quả hiệu suất được thu thập bằng cách sử dụng clang-4.0.0

Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
     Group      |   Experiment    |   Prob. Space   |     Samples     |   Iterations    |    Baseline     |  us/Iteration   | Iterations/sec  | 
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort            | struct          | Null            |              10 |               5 |         1.00000 |    176308.80000 |            5.67 | 
Sort            | tuple           | Null            |              10 |               5 |         1.02699 |    181067.60000 |            5.52 | 
Complete.

Và kết quả hiệu suất được thu thập bằng cách sử dụng gcc-4.9.2

Celero
Timer resolution: 0.001000 us
-----------------------------------------------------------------------------------------------------------------------------------------------
     Group      |   Experiment    |   Prob. Space   |     Samples     |   Iterations    |    Baseline     |  us/Iteration   | Iterations/sec  | 
-----------------------------------------------------------------------------------------------------------------------------------------------
Sort            | struct          | Null            |              10 |               5 |         1.00000 |    198844.80000 |            5.03 | 
Sort            | tuple           | Null            |              10 |               5 |         1.00601 |    200039.80000 |            5.00 | 
Complete.

Bây giờ cấu trúc của chúng tôi nhanh hơn một chút so với một tuple bây giờ (khoảng 3% với clang và ít hơn 1% với gcc), tuy nhiên, chúng tôi cần viết hàm hoán đổi tùy chỉnh cho tất cả các cấu trúc của chúng tôi.


24

Nếu bạn đang sử dụng một số bộ giá trị khác nhau trong mã của mình, bạn có thể thoát khỏi việc cô đọng số bộ chức năng bạn đang sử dụng. Tôi nói điều này bởi vì tôi thường sử dụng các dạng hàm sau:

template<int N>
struct tuple_less{
    template<typename Tuple>
    bool operator()(const Tuple& aLeft, const Tuple& aRight) const{
        typedef typename boost::tuples::element<N, Tuple>::type value_type;
        BOOST_CONCEPT_REQUIRES((boost::LessThanComparable<value_type>));

        return boost::tuples::get<N>(aLeft) < boost::tuples::get<N>(aRight);
    }
};

Điều này có vẻ như quá mức cần thiết nhưng đối với mỗi vị trí trong struct, tôi sẽ phải tạo một đối tượng functor hoàn toàn mới bằng cách sử dụng struct nhưng đối với tuple, tôi chỉ cần thay đổi N. Hơn thế nữa, tôi có thể làm điều này cho mọi tuple thay vì tạo một trình hàm hoàn toàn mới cho mỗi cấu trúc và cho mỗi biến thành viên. Nếu tôi có N cấu trúc với M biến thành viên mà các bộ chức năng NxM, tôi sẽ cần tạo (trường hợp xấu hơn) có thể được cô đọng lại thành một đoạn mã nhỏ.

Đương nhiên, nếu bạn đi theo cách Tuple, bạn cũng sẽ cần tạo Enums để làm việc với chúng:

typedef boost::tuples::tuple<double,double,double> JackPot;
enum JackPotIndex{
    MAX_POT,
    CURRENT_POT,
    MIN_POT
};

và bùng nổ, mã của bạn hoàn toàn có thể đọc được:

double guessWhatThisIs = boost::tuples::get<CURRENT_POT>(someJackPotTuple);

bởi vì nó mô tả chính nó khi bạn muốn lấy các mục chứa bên trong nó.


8
Uh ... C ++ có các con trỏ hàm, vì vậy template <typename C, typename T, T C::*> struct struct_less { template <typename C> bool operator()(C const&, C const&) const; };sẽ có thể. Đánh vần nó ra hơi kém tiện lợi, nhưng nó chỉ được viết một lần.
Matthieu M.

17

Tuple đã xây dựng trong mặc định (cho == và! = Nó so sánh mọi phần tử, cho <. <= ... so sánh đầu tiên, nếu cùng so sánh thứ hai ...): http://en.cppreference.com/w/ cpp / tiện ích / tuple / operator_cmp

chỉnh sửa: như đã lưu ý trong nhận xét Toán tử phi thuyền C ++ 20 cung cấp cho bạn một cách để chỉ định chức năng này bằng một dòng mã (xấu, nhưng vẫn chỉ là một).


1
Trong C ++ 20, điều này đã được khắc phục bằng cách sử dụng toán tử phi thuyền tối thiểu .
John McFarlane

6

Chà, đây là một điểm chuẩn không tạo ra một loạt các bộ giá trị bên trong toán tử struct == (). Hóa ra có một tác động hiệu suất khá đáng kể từ việc sử dụng tuple, như người ta mong đợi vì không có tác động hiệu suất nào từ việc sử dụng POD. (Trình phân giải địa chỉ tìm thấy giá trị trong đường dẫn lệnh trước khi đơn vị logic thậm chí nhìn thấy nó.)

Các kết quả thường gặp khi chạy phần mềm này trên máy của tôi với VS2015CE bằng cài đặt 'Bản phát hành' mặc định:

Structs took 0.0814905 seconds.
Tuples took 0.282463 seconds.

Vui lòng khỉ với nó cho đến khi bạn hài lòng.

#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>

class Timer {
public:
  Timer() { reset(); }
  void reset() { start = now(); }

  double getElapsedSeconds() {
    std::chrono::duration<double> seconds = now() - start;
    return seconds.count();
  }

private:
  static std::chrono::time_point<std::chrono::high_resolution_clock> now() {
    return std::chrono::high_resolution_clock::now();
  }

  std::chrono::time_point<std::chrono::high_resolution_clock> start;

};

struct ST {
  int X;
  int Y;
  double Cost;
  std::string Label;

  bool operator==(const ST &rhs) {
    return
      (X == rhs.X) &&
      (Y == rhs.Y) &&
      (Cost == rhs.Cost) &&
      (Label == rhs.Label);
  }

  bool operator<(const ST &rhs) {
    if(X > rhs.X) { return false; }
    if(Y > rhs.Y) { return false; }
    if(Cost > rhs.Cost) { return false; }
    if(Label >= rhs.Label) { return false; }
    return true;
  }
};

using TP = std::tuple<int, int, double, std::string>;

std::pair<std::vector<ST>, std::vector<TP>> generate() {
  std::mt19937 mt(std::random_device{}());
  std::uniform_int_distribution<int> dist;

  constexpr size_t SZ = 1000000;

  std::pair<std::vector<ST>, std::vector<TP>> p;
  auto& s = p.first;
  auto& d = p.second;
  s.reserve(SZ);
  d.reserve(SZ);

  for(size_t i = 0; i < SZ; i++) {
    s.emplace_back();
    auto& sb = s.back();
    sb.X = dist(mt);
    sb.Y = dist(mt);
    sb.Cost = sb.X * sb.Y;
    sb.Label = std::to_string(sb.Cost);

    d.emplace_back(std::tie(sb.X, sb.Y, sb.Cost, sb.Label));
  }

  return p;
}

int main() {
  Timer timer;

  auto p = generate();
  auto& structs = p.first;
  auto& tuples = p.second;

  timer.reset();
  std::sort(structs.begin(), structs.end());
  double stSecs = timer.getElapsedSeconds();

  timer.reset();
  std::sort(tuples.begin(), tuples.end());
  double tpSecs = timer.getElapsedSeconds();

  std::cout << "Structs took " << stSecs << " seconds.\nTuples took " << tpSecs << " seconds.\n";

  std::cin.get();
}

Cám ơn vì cái này. Tôi nhận thấy rằng khi được tối ưu hóa với -O3, tuplesmất ít thời gian hơn structs.
Simog

3

Vâng, một cấu trúc POD thường có thể được (ab) sử dụng trong việc đọc và tuần tự hóa phân đoạn liền kề cấp thấp. Một bộ tuple có thể được tối ưu hóa hơn trong một số trường hợp nhất định và hỗ trợ nhiều chức năng hơn, như bạn đã nói.

Sử dụng bất cứ điều gì thích hợp hơn cho tình huống, không có sở thích chung. Tôi nghĩ (nhưng tôi chưa đánh giá nó) rằng sự khác biệt về hiệu suất sẽ không đáng kể. Bố cục dữ liệu rất có thể không tương thích và triển khai cụ thể.


3

Theo như "chức năng chung" đi, Boost.Fusion xứng đáng nhận được một số yêu thích ... và đặc biệt là BOOST_FUSION_ADAPT_THER .

Trích xuất từ ​​trang: ABRACADBRA

namespace demo
{
    struct employee
    {
        std::string name;
        int age;
    };
}

// demo::employee is now a Fusion sequence
BOOST_FUSION_ADAPT_STRUCT(
    demo::employee
    (std::string, name)
    (int, age))

Điều này có nghĩa là tất cả các thuật toán Fusion hiện có thể áp dụng cho cấu trúc demo::employee.


CHỈNH SỬA : Về sự khác biệt về hiệu suất hoặc khả năng tương thích với bố cục, tuplebố cục của được xác định triển khai nên không tương thích (và do đó bạn không nên truyền giữa một trong hai đại diện) và nói chung, tôi sẽ mong đợi không có sự khác biệt về hiệu suất (ít nhất là trong Bản phát hành) nhờ nội tuyến của get<N>.


16
Tôi không tin rằng đây là câu trả lời được bình chọn hàng đầu. Nó thậm chí không trả lời câu hỏi. Câu hỏi là về tuples và structs, không phải boost!
gsamaras

@ G.Samaras: Câu hỏi là về sự khác biệt giữa các bộ giá trị và struct, và đáng chú ý là sự phong phú của các thuật toán để thao tác các bộ giá trị so với sự vắng mặt của các thuật toán để thao tác các cấu trúc (bắt đầu bằng cách lặp qua các trường của nó). Câu trả lời này cho thấy rằng khoảng cách này có thể được bắc cầu bằng cách sử dụng Boost.Fusion, mang đến structnhiều thuật toán nhất có trên các bộ giá trị. Tôi đã thêm một chút nổi bật về hai câu hỏi chính xác được hỏi.
Matthieu M.

3

Ngoài ra, bố cục dữ liệu có tương thích với nhau không (thay thế cho nhau)?

Thật kỳ lạ là tôi không thể thấy câu trả lời trực tiếp cho phần này của câu hỏi.

Câu trả lời là: không . Hoặc ít nhất là không đáng tin cậy, vì bố cục của bộ tuple là không xác định.

Thứ nhất, cấu trúc của bạn là Kiểu bố cục chuẩn . Việc sắp xếp, đệm và liên kết của các thành viên được xác định rõ ràng bằng sự kết hợp giữa tiêu chuẩn và nền tảng ABI của bạn.

Nếu một tuple là một loại bố cục tiêu chuẩn và chúng tôi biết các trường được sắp xếp theo thứ tự các loại được chỉ định, chúng tôi có thể chắc chắn rằng nó sẽ khớp với cấu trúc.

Tuple thường được triển khai bằng cách sử dụng kế thừa, theo một trong hai cách: kiểu đệ quy Loki / Modern C ++ Design cũ hoặc kiểu biến thể mới hơn. Không phải là loại Bố cục Chuẩn, vì cả hai đều vi phạm các điều kiện sau:

  1. (trước C ++ 14)

    • không có lớp cơ sở với các thành viên dữ liệu không tĩnh, hoặc

    • không có thành viên dữ liệu không tĩnh nào trong lớp dẫn xuất nhất và nhiều nhất một lớp cơ sở có thành viên dữ liệu không tĩnh

  2. (dành cho C ++ 14 trở lên)

    • Có tất cả các thành viên dữ liệu không tĩnh và các trường bit được khai báo trong cùng một lớp (tất cả trong cơ sở dẫn xuất hoặc tất cả trong một số cơ sở)

vì mỗi lớp cơ sở lá chứa một phần tử tuple duy nhất (NB. một tuple phần tử đơn có thể một kiểu bố trí tiêu chuẩn, mặc dù không phải là một kiểu rất hữu ích). Vì vậy, chúng tôi biết tiêu chuẩn không đảm bảo tuple có đệm hoặc căn chỉnh giống như cấu trúc.

Ngoài ra, cần lưu ý rằng bộ tuple kiểu đệ quy cũ hơn thường sẽ sắp xếp các thành viên dữ liệu theo thứ tự ngược lại.

Thông thường, nó đôi khi đã hoạt động trong thực tế đối với một số trình biên dịch và tổ hợp các loại trường trong quá khứ (trong một trường hợp, sử dụng bộ giá trị đệ quy, sau khi đảo ngược thứ tự trường). Nó chắc chắn không hoạt động đáng tin cậy (trên các trình biên dịch, phiên bản, v.v.) bây giờ và không bao giờ được đảm bảo ngay từ đầu.


1

Không nên có sự khác biệt về hiệu suất (thậm chí là không đáng kể). Ít nhất trong trường hợp bình thường, chúng sẽ dẫn đến bố cục bộ nhớ giống nhau. Tuy nhiên, việc casting giữa họ có lẽ không bắt buộc phải hoạt động (mặc dù tôi đoán rằng bình thường vẫn có một cơ hội khá tốt).


4
Trên thực tế, tôi nghĩ rằng có thể có một sự khác biệt nhỏ. A structphải phân bổ ít nhất 1 byte cho mỗi subobject trong khi tôi nghĩ rằng a tuplecó thể thoát khỏi việc tối ưu hóa các đối tượng trống. Ngoài ra, liên quan đến việc đóng gói và căn chỉnh, có thể là các bộ giá có nhiều thời gian hơn.
Matthieu M.

1

Kinh nghiệm của tôi là theo thời gian, chức năng bắt đầu tăng dần trên các loại (như cấu trúc POD) từng là người giữ dữ liệu thuần túy. Những thứ như một số sửa đổi nhất định không yêu cầu kiến ​​thức bên trong về dữ liệu, duy trì sự bất biến, v.v.

Đó là một điều tốt; nó là nền tảng của hướng đối tượng. Đó là lý do tại sao C với các lớp được phát minh. Việc sử dụng các bộ sưu tập dữ liệu thuần túy như bộ giá trị không được mở cho phần mở rộng hợp lý như vậy; cấu trúc là. Đó là lý do tại sao tôi hầu như luôn chọn cấu trúc.

Liên quan là giống như tất cả các "đối tượng dữ liệu mở", bộ giá trị vi phạm mô hình ẩn thông tin. Bạn không thể thay đổi điều đó sau này mà không bỏ sỉ tuple. Với một cấu trúc, bạn có thể chuyển dần sang các chức năng truy cập.

Một vấn đề khác là an toàn kiểu và mã tự ghi lại. Nếu hàm của bạn nhận được một đối tượng kiểu inbound_telegramhoặc location_3Dnó rõ ràng; nếu nó nhận được một unsigned char *hoặc tuple<double, double, double>nó không: bức điện có thể được gửi đi và tuple có thể là một bản dịch thay vì một vị trí, hoặc có thể là các kết quả nhiệt độ tối thiểu từ cuối tuần dài. Có, bạn có thể đánh máy để làm rõ ý định nhưng điều đó không thực sự ngăn cản bạn vượt qua nhiệt độ.

Những vấn đề này có xu hướng trở nên quan trọng trong các dự án vượt quá một quy mô nhất định; những nhược điểm của bộ giá trị và lợi thế của các lớp phức tạp trở nên không nhìn thấy được và thực sự là một chi phí trong các dự án nhỏ. Bắt đầu với các lớp thích hợp ngay cả đối với các tổng hợp dữ liệu nhỏ không dễ thấy sẽ trả cổ tức muộn.

Tất nhiên, một chiến lược khả thi sẽ là sử dụng một người giữ dữ liệu thuần túy làm nhà cung cấp dữ liệu cơ bản cho một trình bao bọc lớp cung cấp các hoạt động trên dữ liệu đó.


1

Đừng lo lắng về tốc độ hoặc bố cục, đó là tối ưu hóa nano, và phụ thuộc vào trình biên dịch, và không bao giờ có đủ sự khác biệt để ảnh hưởng đến quyết định của bạn.

Bạn sử dụng cấu trúc cho những thứ thuộc về nhau một cách có ý nghĩa để tạo thành một tổng thể.

Bạn sử dụng một bộ giá trị cho những thứ trùng hợp với nhau. Bạn có thể sử dụng một tuple một cách tự nhiên trong mã của mình.


1

Đánh giá bằng các câu trả lời khác, tốt nhất là việc cân nhắc hiệu suất là tối thiểu.

Vì vậy, nó thực sự nên đi xuống tính thực tế, khả năng đọc và khả năng bảo trì. Và structnói chung là tốt hơn vì nó tạo ra các loại dễ đọc và dễ hiểu hơn.

Đôi khi, một std::tuple(hoặc thậm chí std::pair) có thể cần thiết để xử lý mã theo cách chung chung. Ví dụ, một số hoạt động liên quan đến các gói tham số khác nhau sẽ không thể thực hiện được nếu không có những thứ như thế std::tuple. std::tielà một ví dụ tuyệt vời về thời điểm std::tuplecó thể cải thiện mã (trước C ++ 20).

Nhưng bất cứ nơi nào bạn có thể sử dụng a struct, có lẽ bạn nên sử dụng a struct. Nó sẽ cung cấp ý nghĩa ngữ nghĩa cho các phần tử thuộc loại của bạn. Đó là vô giá trong việc hiểu và sử dụng loại. Đổi lại, điều này có thể giúp tránh những sai lầm ngớ ngẩn:

// hard to get wrong; easy to understand
cat.arms = 0;
cat.legs = 4;

// easy to get wrong; hard to understand
std::get<0>(cat) = 0;
std::get<1>(cat) = 4;

0

Tôi biết đó là một chủ đề cũ, tuy nhiên bây giờ tôi chuẩn bị đưa ra quyết định về một phần dự án của mình: tôi nên sử dụng tuple-way hay struct-way. Sau khi đọc chủ đề này, tôi có một số ý tưởng.

  1. Về wheaties và kiểm tra hiệu suất: xin lưu ý rằng bạn thường có thể sử dụng memcpy, memset và các thủ thuật tương tự cho cấu trúc. Điều này sẽ làm cho hiệu suất tốt hơn NHIỀU so với bộ giá trị.

  2. Tôi thấy một số lợi thế trong bộ giá trị:

    • Bạn có thể sử dụng bộ giá trị để trả về một tập hợp các biến từ hàm hoặc phương thức và giảm một số kiểu bạn sử dụng.
    • Dựa trên thực tế là tuple đã xác định trước các toán tử <, ==,>, bạn cũng có thể sử dụng tuple làm khóa trong bản đồ hoặc hash_map sẽ tiết kiệm chi phí hơn nhiều mà struct nơi bạn cần triển khai các toán tử này.

Tôi đã tìm kiếm trên web và cuối cùng đến được trang này: https://arne-mertz.de/2017/03/smelly-pair-tuple/

Nói chung tôi đồng ý với một kết luận cuối cùng từ trên.


1
Điều này nghe giống như những gì bạn đang làm và không phải là câu trả lời cho câu hỏi cụ thể đó, hoặc?
Dieter Meemken

Không có gì ngăn cản bạn sử dụng memcpy với các bộ giá trị.
Peter - Phục hồi Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.