सी ++ ट्यूपल बनाम संरचना


95

क्या std::tupleडेटा और केवल डेटा के उपयोग में कोई अंतर है struct?

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

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

मैंने जो ऑनलाइन पाया है, मैंने पाया कि दो प्रमुख अंतर हैं: structअधिक पठनीय है, जबकि tupleकई सामान्य कार्य हैं जिनका उपयोग किया जा सकता है। क्या कोई महत्वपूर्ण प्रदर्शन अंतर होना चाहिए? इसके अलावा, क्या डेटा लेआउट एक-दूसरे के साथ संगत है (परस्पर रूप से डाली गई)?


मैंने अभी टिप्पणी की है कि मैं कास्ट प्रश्न के बारे में भूल गया था : कार्यान्वयन की tupleपरिभाषा परिभाषित है, इसलिए यह आपके कार्यान्वयन पर निर्भर करता है। व्यक्तिगत रूप से, मैं इस पर भरोसा नहीं करूंगा ।
मैथ्यू एम।

जवाबों:


31

टपल और संरचना के बारे में हमारी समान चर्चा है और मैं टपल और संरचना के बीच प्रदर्शन के अंतर की पहचान करने के लिए अपने एक सहयोगी की मदद से कुछ सरल बेंचमार्क लिखता हूं। हम पहले एक डिफ़ॉल्ट संरचना और एक ट्यूपल के साथ शुरू करते हैं।

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>;

तब हम अपनी सरल संरचना और टपल के प्रदर्शन की तुलना करने के लिए सेलेरो का उपयोग करते हैं। नीचे gcc-4.9.2 और 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);
}

क्लैंग-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.

और प्रदर्शन परिणाम 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.

उपरोक्त परिणामों से हम स्पष्ट रूप से देख सकते हैं

  • ट्यूल एक डिफ़ॉल्ट संरचना से तेज है

  • क्लैंग द्वारा बाइनरी प्रोडक्शन में उच्च प्रदर्शन है जो कि जीसीसी का है। क्लैंग-बनाम-जीसीसी इस चर्चा का उद्देश्य नहीं है, इसलिए मैं विस्तार से गोता नहीं लगाऊंगा।

हम सभी जानते हैं कि प्रत्येक एकल संरचना परिभाषा के लिए एक == या <या> ऑपरेटर लिखना एक दर्दनाक और छोटी गाड़ी का काम होगा। हमारे कस्टम तुलनित्र को std :: टाई और फिर से हमारे बेंचमार्क का उपयोग करने दें।

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.

अब हम देख सकते हैं कि std :: टाई का उपयोग हमारे कोड को अधिक सुरुचिपूर्ण बनाता है और गलती करना कठिन है, हालांकि, हम लगभग 1% प्रदर्शन को ढीला कर देंगे। मैं अब के लिए std :: टाई सॉल्यूशन के साथ रहूंगा क्योंकि मुझे भी स्वनिर्धारित तुलनित्र के साथ फ्लोटिंग पॉइंट नंबरों की तुलना करने के बारे में एक चेतावनी मिलती है।

अब तक हमारे पास हमारे संरचना कोड को तेजी से चलाने के लिए कोई समाधान नहीं है। आइए हम स्वैप समारोह पर एक नज़र डालें और इसे फिर से लिखें कि क्या हम कोई प्रदर्शन हासिल कर सकते हैं:

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);
    }
};

क्लेंग-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.

और प्रदर्शन परिणाम 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.

अब हमारी संरचना एक टपल की तुलना में थोड़ी तेज है (क्लैंग के साथ लगभग 3% और जीसीसी के साथ 1% से कम), हालांकि, हमें अपनी सभी संरचनाओं के लिए अपने अनुकूलित स्वैप फ़ंक्शन को लिखने की आवश्यकता है।


24

यदि आप अपने कोड में कई अलग-अलग tuples का उपयोग कर रहे हैं, तो आप अपने द्वारा उपयोग किए जा रहे फ़ंक्शंस की संख्या को संघनित करने से दूर हो सकते हैं। मैं यह कहता हूं क्योंकि मैंने अक्सर फंक्शंस के निम्नलिखित रूपों का उपयोग किया है:

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);
    }
};

यह ओवरकिल की तरह लग सकता है, लेकिन संरचना के भीतर प्रत्येक जगह के लिए मुझे एक पूरी तरह से एक नए फ़्यूक्टर ऑब्जेक्ट का उपयोग करना होगा, लेकिन एक ट्यूपल के लिए, मैं बस बदलता हूं N। इससे बेहतर, मैं प्रत्येक एकल के लिए यह कर सकता हूं क्योंकि प्रत्येक संरचना के लिए और प्रत्येक सदस्य चर के लिए एक नया फ़नकार बनाने का विरोध किया गया है। अगर मेरे पास M सदस्य चर के साथ N संरचना है जिसे NxM फंक्शनलर्स बनाने की आवश्यकता होगी (बदतर स्थिति) जो कोड के एक छोटे से नीचे संघनित हो सकता है।

स्वाभाविक रूप से, यदि आप टुपल रास्ते से जाने वाले हैं, तो आपको उनके साथ काम करने के लिए एनम बनाने की भी आवश्यकता है:

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

और बूम, आप कोड पूरी तरह से पठनीय हैं:

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

क्योंकि यह स्वयं का वर्णन करता है जब आप इसके भीतर मौजूद वस्तुओं को प्राप्त करना चाहते हैं।


8
उह ... सी ++ में फ़ंक्शन पॉइंटर्स हैं, इसलिए template <typename C, typename T, T C::*> struct struct_less { template <typename C> bool operator()(C const&, C const&) const; };संभव होना चाहिए। इसे बाहर वर्तनी थोड़ा कम सुविधाजनक है, लेकिन यह केवल एक बार लिखा गया है।
मैथ्यू एम।

17

Tuple ने डिफ़ॉल्ट रूप से बनाया है (== के लिए! =! = यह हर तत्व की तुलना करता है, <के लिए। <= ... पहले की तुलना करता है, यदि वही दूसरी तुलना करता है ...) तुलनाकर्ता: http://en.cppreference.com/w/ सीपीपी / उपयोगिता / टपल / operator_cmp

संपादित करें: जैसा कि टिप्पणी में उल्लेख किया गया है C ++ 20 स्पेसशिप ऑपरेटर आपको इस कार्यक्षमता को एक (बदसूरत, लेकिन अभी भी सिर्फ एक) कोड के साथ निर्दिष्ट करने का एक तरीका देता है।


1
सी ++ 20 में, यह स्पेसशिप ऑपरेटर का उपयोग करके न्यूनतम बॉयलरप्लेट के साथ बनाया गया है
जॉन मैकफर्लेन

6

ठीक है, यहाँ एक बेंचमार्क है जो स्ट्रक्चर ऑपरेटर == () के अंदर ट्यूपल्स का एक गुच्छा नहीं बनाता है। पता चलता है कि टपल का उपयोग करने से काफी महत्वपूर्ण प्रदर्शन प्रभाव पड़ता है, क्योंकि कोई यह उम्मीद करेगा कि PODs के उपयोग से कोई प्रदर्शन प्रभाव नहीं है। (पता रिज़ॉल्वर तर्क इकाई में पहले कभी भी इसे देखता है, निर्देश पाइपलाइन में मूल्य पाता है।)

डिफ़ॉल्ट 'रिलीज़' सेटिंग का उपयोग करके VS2015CE के साथ मेरी मशीन पर इसे चलाने से सामान्य परिणाम:

Structs took 0.0814905 seconds.
Tuples took 0.282463 seconds.

जब तक आप संतुष्ट नहीं हो जाते, तब तक उसके साथ बंदर करें।

#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();
}

इसके लिए धन्यवाद। मैंने देखा कि जब के साथ अनुकूलित -O3, tuplesसे कम समय लिया structs
सिमोग

3

ठीक है, एक पीओडी संरचना अक्सर निम्न-स्तरीय सन्निहित चंक पढ़ने और क्रमांकन में उपयोग (एब) हो सकती है। जैसा कि आपने कहा था कि कुछ स्थितियों में एक ट्यूपल अधिक अनुकूलित हो सकता है और अधिक कार्यों का समर्थन कर सकता है।

स्थिति के लिए जो भी अधिक उपयुक्त हो उसका उपयोग करें, कोई सामान्य प्राथमिकता नहीं है। मुझे लगता है (लेकिन मैंने इसे बेंचमार्क नहीं किया है) कि प्रदर्शन अंतर महत्वपूर्ण नहीं होंगे। डेटा लेआउट सबसे अधिक संभावना संगत और कार्यान्वयन विशिष्ट नहीं है।


3

जहां तक ​​"जेनेरिक फंक्शन" की बात है, Boost.Fusion कुछ प्यार के हकदार हैं ... और विशेष रूप से BOOST_FUSION_ADAPT_STRUCT

पृष्ठ से तेजस्वी: 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))

इसका मतलब है कि सभी फ्यूजन एल्गोरिदम अब संरचना पर लागू होते हैं demo::employee


संपादित करें : प्रदर्शन अंतर या लेआउट संगतता के बारे में, tuple'' लेआउट कार्यान्वयन को परिभाषित किया गया है इसलिए संगत नहीं है (और इस प्रकार आपको या तो प्रतिनिधित्व के बीच नहीं डालना चाहिए) और सामान्य तौर पर मुझे उम्मीद है कि कोई अंतर प्रदर्शन-वार (कम से कम रिलीज में) नहीं होगा। की इनलाइनिंग get<N>


16
मुझे विश्वास नहीं है कि यह शीर्ष मतदान का जवाब है। यह प्रश्न का उत्तर भी नहीं देता है। सवाल tupleएस एंड structएस के बारे में है , बढ़ावा नहीं!
gsamaras

@ G.Samaras: सवाल ट्यूपल्स के बीच अंतर के बारे में है struct, और विशेष रूप से एल्गोरिदम की अनुपस्थिति के लिए एल्गोरिदम की अनुपस्थिति के खिलाफ संरचना में हेरफेर करने के लिए (अपने क्षेत्रों में पुनरावृत्ति करके शुरुआत) बहुतायत से है। यह उत्तर दर्शाता है कि बूस्ट.फ्यूजन का उपयोग करके इस अंतर को पाटा जा सकता है, structtuples पर उतने ही एल्गोरिदम लाए जा सकते हैं। मैंने पूछे गए सटीक दो प्रश्नों पर एक छोटा सा ब्लर जोड़ा।
Matthieu M.

3

इसके अलावा, क्या डेटा लेआउट एक-दूसरे के साथ संगत है (परस्पर रूप से डाली गई)?

अजीब तरह से मैं सवाल के इस भाग के लिए एक सीधी प्रतिक्रिया नहीं देख सकता।

जवाब है: नहीं । या कम से कम मज़बूती से नहीं, क्योंकि ट्यूल का लेआउट अनिर्दिष्ट है।

सबसे पहले, आपकी संरचना एक मानक लेआउट प्रकार है । मानक, और आपके मंच ABI के संयोजन से सदस्यों के आदेश, गद्दी और संरेखण को अच्छी तरह से परिभाषित किया गया है।

यदि एक ट्यूपल एक मानक लेआउट प्रकार था, और हमें पता था कि फ़ील्ड्स को उस क्रम में बाहर रखा गया है जिस प्रकार के निर्दिष्ट हैं, तो हमें कुछ विश्वास हो सकता है कि यह संरचना से मेल खाएगा।

पुराने तरीके से पुराने लोकी / आधुनिक C ++ डिज़ाइन पुनरावर्ती शैली, या नए वैरेडिक शैली: टुपल को सामान्यतः दो तरीकों में से एक का उपयोग करके लागू किया जाता है। न तो एक मानक लेआउट प्रकार है, क्योंकि दोनों निम्नलिखित शर्तों का उल्लंघन करते हैं:

  1. (C ++ 14 से पहले)

    • गैर-स्थैतिक डेटा सदस्यों के साथ कोई आधार वर्ग नहीं है, या

    • सबसे अधिक व्युत्पन्न वर्ग में और गैर-स्थैतिक डेटा सदस्यों के साथ अधिकांश एक बेस क्लास में कोई गैर-स्थैतिक डेटा सदस्य नहीं है

  2. (C ++ 14 और बाद के लिए)

    • सभी गैर-स्थैतिक डेटा सदस्यों और बिट-फ़ील्ड को एक ही वर्ग में घोषित किया गया है (या तो सभी या किसी आधार में सभी)

चूंकि प्रत्येक लीफ बेस क्लास में एक एकल टपल तत्व (NB) होता है एक मानक लेआउट प्रकार, नहीं एक बहुत ही उपयोगी यद्यपि)। इसलिए, हम जानते हैं कि मानक की गारंटी नहीं है कि ट्यूपल की संरचना के समान पैडिंग या संरेखण है।

इसके अतिरिक्त, यह ध्यान देने योग्य है कि पुराने पुनरावर्ती-शैली का टपल आमतौर पर उल्टे क्रम में डेटा सदस्यों को बाहर करेगा।

पूर्वकाल में, यह कभी-कभी अतीत में कुछ कंपाइलरों और क्षेत्र प्रकारों के संयोजन के लिए अभ्यास में काम करता है (एक मामले में, पुनरावर्ती टुपल्स का उपयोग करके, फ़ील्ड क्रम को उलटने के बाद)। यह निश्चित रूप से मज़बूती से काम नहीं करता है (संकलक, संस्करण आदि के पार), और पहली जगह में इसकी गारंटी कभी नहीं थी।


1

एक प्रदर्शन अंतर (यहां तक ​​कि एक तुच्छ) नहीं होना चाहिए। कम से कम सामान्य मामले में, वे एक ही मेमोरी लेआउट में परिणाम करेंगे। बहरहाल, शायद उनके बीच काम करने की आवश्यकता नहीं है (हालांकि मुझे लगता है कि यह एक बहुत अच्छा मौका होगा जो सामान्य रूप से होगा)।


4
वास्तव में मुझे लगता है कि एक छोटा सा अंतर हो सकता है। एक struct, जबकि मुझे लगता है कि एक प्रत्येक subobject के लिए कम से कम 1 बाइट आवंटित चाहिए tupleखाली वस्तुओं बाहर के अनुकूलन के साथ भाग प्राप्त कर सकते हैं। इसके अलावा, पैकिंग और संरेखण के संबंध में, यह हो सकता है कि ट्यूपल्स में अधिक लीव हो।
मैथ्यू एम।

1

मेरा अनुभव है कि समय के साथ कार्यक्षमता प्रकारों (जैसे POD स्ट्रक्चर्स) पर रेंगना शुरू कर देती है जो शुद्ध डेटा धारक हुआ करते थे। कुछ संशोधनों जैसी चीजें जिनके लिए डेटा के अंदर ज्ञान की आवश्यकता नहीं होनी चाहिए, हमलावरों को बनाए रखना आदि।

यह एक अच्छी बात है; यह ऑब्जेक्ट ओरिएंटेशन की नींव है। यही कारण है कि वर्गों के साथ सी का आविष्कार किया गया था। टुपल्स जैसे शुद्ध डेटा संग्रह का उपयोग करना इस तरह के तार्किक विस्तार के लिए खुला नहीं है; संरचनाएं हैं। यही कारण है कि मैं लगभग हमेशा के लिए विकल्प चुनूंगा।

संबंधित यह है कि सभी "खुले डेटा ऑब्जेक्ट्स" की तरह, टुपल्स सूचना छिपाने के प्रतिमान का उल्लंघन करते हैं। आप बाद में टपल थोक फेंकने के बिना इसे बदल नहीं सकते । एक संरचना के साथ, आप धीरे-धीरे पहुंच कार्यों की ओर बढ़ सकते हैं।

एक अन्य मुद्दा प्रकार सुरक्षा और स्व-दस्तावेजीकरण कोड है। यदि आपके फ़ंक्शन को ऑब्जेक्ट का प्रकार प्राप्त होता है inbound_telegramया location_3Dयह स्पष्ट है; अगर यह एक unsigned char *या प्राप्त करता हैtuple<double, double, double> यह नहीं है: टेलीग्राम आउटबाउंड हो सकता है, और ट्यूपल स्थान के बजाय अनुवाद हो सकता है, या शायद लंबे सप्ताहांत से न्यूनतम तापमान रीडिंग। हां, आप इरादे स्पष्ट करने के लिए टाइप कर सकते हैं लेकिन यह वास्तव में आपको तापमान को पार करने से नहीं रोकता है।

ये मुद्दे उन परियोजनाओं में महत्वपूर्ण हो जाते हैं जो एक निश्चित आकार से अधिक होती हैं; टुपल्स के नुकसान और विस्तृत कक्षाओं के फायदे दिखाई नहीं देते हैं और वास्तव में छोटी परियोजनाओं में एक उपरि हैं। असंगत छोटे डेटा समुच्चय के लिए भी उचित वर्गों के साथ शुरू करना देर से लाभांश का भुगतान करता है।

बेशक एक व्यवहार्य रणनीति के लिए एक शुद्ध डेटा धारक का उपयोग करना होगा जो कि क्लास रैपर के लिए अंतर्निहित डेटा प्रदाता के रूप में होता है जो उस डेटा पर संचालन प्रदान करता है।


1

गति या लेआउट के बारे में चिंता न करें, यह नैनो-अनुकूलन है, और संकलक पर निर्भर करता है, और आपके निर्णय को प्रभावित करने के लिए पर्याप्त अंतर नहीं है।

आप उन चीजों के लिए एक संरचना का उपयोग करते हैं जो सार्थक रूप से संपूर्ण बनाने के लिए एक साथ हैं।

आप उन चीजों के लिए एक टपल का उपयोग करते हैं जो संयोग से एक साथ हैं। आप अपने कोड में सहजता से टपल का उपयोग कर सकते हैं।


1

अन्य उत्तरों को देखते हुए, प्रदर्शन के विचार न्यूनतम हैं।

तो यह वास्तव में व्यावहारिकता, पठनीयता और स्थिरता के लिए नीचे आना चाहिए। और structआम तौर पर बेहतर होता है क्योंकि यह उन प्रकारों को बनाता है जिन्हें पढ़ना और समझना आसान है।

कभी-कभी, एक std::tuple(या यहां तक ​​कि std::pair) अत्यधिक सामान्य तरीके से कोड से निपटने के लिए आवश्यक हो सकता है। उदाहरण के लिए, वैरैडिक पैरामीटर पैक्स से जुड़े कुछ ऑपरेशन बिना कुछ किए असंभव होंगे std::tuplestd::tieजब std::tupleकोड में सुधार हो सकता है (C ++ 20 से पहले) का एक शानदार उदाहरण है ।

लेकिन कहीं भी आप एक का उपयोग कर सकते हैं struct, आप शायद एक का उपयोग करना चाहिएstruct । यह आपके प्रकार के तत्वों पर अर्थ अर्थ देगा। यह समझने और प्रकार का उपयोग करने में अमूल्य है। बदले में, यह मूर्खतापूर्ण गलतियों से बचने में मदद कर सकता है:

// 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

मुझे पता है कि यह एक पुराना विषय है, हालांकि अब मैं अपनी परियोजना के हिस्से के बारे में निर्णय लेने वाला हूं: क्या मुझे ट्यूल-वे या स्ट्रक्चर-वे पर जाना चाहिए। इस सूत्र को पढ़ने के बाद मेरे पास कुछ विचार हैं।

  1. गेहूं और प्रदर्शन परीक्षण के बारे में: कृपया ध्यान दें कि आप आम तौर पर मेम्फिश, मेमसेट और समान ट्रिक्स का उपयोग कर सकते हैं। यह प्रदर्शन को ट्यूपल्स की तुलना में बेहतर बना देगा।

  2. मैं tuples में कुछ फायदे देखते हैं:

    • आप फ़ंक्शन या विधि से चर का संग्रह वापस करने के लिए tuples का उपयोग कर सकते हैं और आपके द्वारा उपयोग किए जाने वाले कई प्रकारों को घटा सकते हैं।
    • इस तथ्य के आधार पर कि टपल को पूर्वनिर्धारित किया गया है <, ==,> परिचालक आप नक्शे या हैश_मैप में एक कुंजी के रूप में टपल का भी उपयोग कर सकते हैं, जो कि अधिक लागत प्रभावी है उस संरचना को जहां आपको इन ऑपरेटरों को लागू करने की आवश्यकता है।

मैंने वेब खोज लिया है और अंततः इस पृष्ठ पर पहुंच गया है: https://arne-mertz.de/2017/03/smelly-pair-bupup/

आम तौर पर मैं ऊपर से एक अंतिम निष्कर्ष से सहमत हूं।


1
यह अधिक लगता है कि आप किस बारे में काम कर रहे हैं और उस विशिष्ट प्रश्न का उत्तर नहीं है, या?
डाइटर मीमकेन

टुपल्स के साथ मेम्पी का उपयोग करने से कुछ भी नहीं रहता है।
पीटर - मोनिका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.