7/25/2025

C++ tuple vs vector, Tutorial

 

// ============================================================================
// SIMPLE COMPARISON: TUPLE vs VECTOR
// When to use which one and why they're different
// ============================================================================

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

// ============================================================================
// VECTOR: Dynamic Array of SAME TYPE
// ============================================================================

void vector_example() {
std::cout << "=== VECTOR EXAMPLE ===" << std::endl;
// Vector holds multiple values of THE SAME TYPE
std::vector<int> numbers = {10, 20, 30, 40, 50};
std::cout << "Vector contents: ";
for (size_t i = 0; i < numbers.size(); i++) {
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
// Add more elements
numbers.push_back(60);
numbers.push_back(70);
std::cout << "After adding elements: ";
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Vector size: " << numbers.size() << std::endl;
std::cout << "Can grow/shrink at runtime: YES" << std::endl;
std::cout << "All elements same type: YES (int)" << std::endl;
}

// ============================================================================
// TUPLE: Fixed Collection of DIFFERENT TYPES
// ============================================================================

void tuple_example() {
std::cout << "\n=== TUPLE EXAMPLE ===" << std::endl;
// Tuple holds DIFFERENT TYPES in fixed positions
std::tuple<int, float, std::string, bool> data = {42, 3.14f, "hello", true};
std::cout << "Tuple contents:" << std::endl;
std::cout << "Position 0 (int): " << std::get<0>(data) << std::endl;
std::cout << "Position 1 (float): " << std::get<1>(data) << std::endl;
std::cout << "Position 2 (string): " << std::get<2>(data) << std::endl;
std::cout << "Position 3 (bool): " << std::get<3>(data) << std::endl;
// Cannot add elements - size is fixed at compile time
// data.push_back(something); // ERROR! No such method
std::cout << "Tuple size: " << std::tuple_size_v<decltype(data)> << std::endl;
std::cout << "Can grow/shrink at runtime: NO" << std::endl;
std::cout << "All elements same type: NO (int, float, string, bool)" << std::endl;
}

// ============================================================================
// SIDE-BY-SIDE COMPARISON
// ============================================================================

void comparison() {
std::cout << "\n=== SIDE-BY-SIDE COMPARISON (marearts.com)===" << std::endl;
// VECTOR: All same type, dynamic size
std::vector<double> grades = {85.5, 92.0, 78.5, 95.0};
// TUPLE: Different types, fixed size
std::tuple<std::string, int, double, char> student = {"Alice", 20, 89.5, 'A'};
std::cout << "VECTOR (grades):" << std::endl;
std::cout << " Type: vector<double>" << std::endl;
std::cout << " Values: ";
for (double grade : grades) {
std::cout << grade << " ";
}
std::cout << std::endl;
std::cout << " Access: grades[0], grades[1], grades[2]..." << std::endl;
std::cout << " Can add more: YES (grades.push_back(88.0))" << std::endl;
std::cout << "\nTUPLE (student info):" << std::endl;
std::cout << " Type: tuple<string, int, double, char>" << std::endl;
std::cout << " Values: " << std::get<0>(student) << ", "
<< std::get<1>(student) << ", "
<< std::get<2>(student) << ", "
<< std::get<3>(student) << std::endl;
std::cout << " Access: std::get<0>(student), std::get<1>(student)..." << std::endl;
std::cout << " Can add more: NO (fixed at compile time)" << std::endl;
}

// ============================================================================
// WHEN TO USE WHICH?
// ============================================================================

void when_to_use() {
std::cout << "\n=== WHEN TO USE WHICH? ===" << std::endl;
std::cout << "USE VECTOR WHEN:" << std::endl;
std::cout << " ✓ All elements are the same type" << std::endl;
std::cout << " ✓ You don't know size at compile time" << std::endl;
std::cout << " ✓ Size can change during runtime" << std::endl;
std::cout << " ✓ You want to loop through elements" << std::endl;
std::cout << " ✓ Examples: list of numbers, array of names, dynamic data" << std::endl;
std::cout << "\nUSE TUPLE WHEN:" << std::endl;
std::cout << " ✓ Elements have different types" << std::endl;
std::cout << " ✓ Size is fixed and known at compile time" << std::endl;
std::cout << " ✓ Each position has specific meaning" << std::endl;
std::cout << " ✓ You want type safety for each element" << std::endl;
std::cout << " ✓ Examples: coordinates (x,y), person data (name,age,score), config settings" << std::endl;
}

// ============================================================================
// PRACTICAL EXAMPLES
// ============================================================================

void practical_examples() {
std::cout << "\n=== PRACTICAL EXAMPLES ===" << std::endl;
// VECTOR EXAMPLES (same type, dynamic)
std::cout << "VECTOR use cases:" << std::endl;
std::vector<int> test_scores; // Dynamic list of test scores
test_scores.push_back(85);
test_scores.push_back(92);
test_scores.push_back(78); // Can keep adding
std::vector<std::string> names = {"Alice", "Bob", "Charlie"}; // List of names
std::cout << " Test scores: ";
for (int score : test_scores) std::cout << score << " ";
std::cout << std::endl;
// TUPLE EXAMPLES (different types, fixed)
std::cout << "\nTUPLE use cases:" << std::endl;
std::tuple<int, int> coordinates = {10, 20}; // 2D point (x, y)
std::tuple<std::string, int, char> student = {"Bob", 19, 'B'}; // Name, age, grade
std::tuple<float, float, float> rgb_color = {0.8f, 0.2f, 0.5f}; // Red, green, blue
auto [x, y] = coordinates; // C++17 structured binding
std::cout << " Coordinates: (" << x << ", " << y << ")" << std::endl;
std::cout << " Student: " << std::get<0>(student) << ", age " << std::get<1>(student)
<< ", grade " << std::get<2>(student) << std::endl;
}

// ============================================================================
// MEMORY AND PERFORMANCE
// ============================================================================

void memory_and_performance() {
std::cout << "\n=== MEMORY & PERFORMANCE ===" << std::endl;
// Vector - dynamic allocation
std::vector<int> vec = {1, 2, 3, 4, 5};
// Tuple - compile-time known, usually stack allocated
std::tuple<int, int, int, int, int> tup = {1, 2, 3, 4, 5};
std::cout << "VECTOR:" << std::endl;
std::cout << " Memory: Heap allocated (dynamic)" << std::endl;
std::cout << " Access: Runtime indexing vec[i]" << std::endl;
std::cout << " Size overhead: Stores capacity + size info" << std::endl;
std::cout << " Performance: Slight overhead for bounds checking" << std::endl;
std::cout << "\nTUPLE:" << std::endl;
std::cout << " Memory: Usually stack allocated (compile-time size)" << std::endl;
std::cout << " Access: Compile-time indexing std::get<N>()" << std::endl;
std::cout << " Size overhead: None (just the data)" << std::endl;
std::cout << " Performance: Maximum efficiency (compile-time optimized)" << std::endl;
}

// ============================================================================
// CANNOT MIX - ERROR EXAMPLES
// ============================================================================

void error_examples() {
std::cout << "\n=== WHAT YOU CANNOT DO ===" << std::endl;
std::cout << "VECTOR limitations:" << std::endl;
std::cout << " ✗ Cannot mix types: vector<int, string> // COMPILER ERROR" << std::endl;
std::cout << " ✗ All elements must be same type" << std::endl;
std::cout << "\nTUPLE limitations:" << std::endl;
std::cout << " ✗ Cannot resize: tuple.push_back() // NO SUCH METHOD" << std::endl;
std::cout << " ✗ Cannot loop easily (no iterators)" << std::endl;
std::cout << " ✗ Must know position at compile time: tuple[i] // ERROR" << std::endl;
// Demonstrate what works
std::vector<int> good_vector = {1, 2, 3}; // ✓ Same type
// std::vector<int, string> bad_vector; // ✗ COMPILER ERROR
std::tuple<int, std::string> good_tuple = {42, "hello"}; // ✓ Different types
// good_tuple.push_back(123); // ✗ NO SUCH METHOD
std::cout << "\nWorking examples:" << std::endl;
std::cout << " Vector: " << good_vector[0] << ", " << good_vector[1] << std::endl;
std::cout << " Tuple: " << std::get<0>(good_tuple) << ", " << std::get<1>(good_tuple) << std::endl;
}

// ============================================================================
// MAIN FUNCTION
// ============================================================================

int main() {
std::cout << "TUPLE vs VECTOR - Simple Comparison" << std::endl;
std::cout << "====================================" << std::endl;
vector_example();
tuple_example();
comparison();
when_to_use();
practical_examples();
memory_and_performance();
error_examples();
std::cout << "\n=== QUICK SUMMARY ===" << std::endl;
std::cout << "VECTOR = Same type + Dynamic size + Runtime flexibility" << std::endl;
std::cout << "TUPLE = Different types + Fixed size + Compile-time safety" << std::endl;
std::cout << "\nThey solve different problems!" << std::endl;
return 0;
}

// ============================================================================
// KEY DIFFERENCES SUMMARY:
// ============================================================================
//
// VECTOR<T>:
// - All elements type T (same type)
// - Dynamic size (can grow/shrink)
// - Runtime access: vec[i]
// - Memory: heap allocated
// - Use for: lists, arrays, collections
//
// TUPLE<T1, T2, T3>:
// - Each element different type
// - Fixed size (compile-time)
// - Compile-time access: std::get<N>()
// - Memory: usually stack
// - Use for: structured data, coordinates, configs
//
// CHOOSE BASED ON:
// - Same vs different types?
// - Dynamic vs fixed size?
// - Runtime vs compile-time access?

No comments:

Post a Comment