C++ Array模板类正确创建方法求教(附代码)
Hey there! Let's walk through fixing your C++ Array template class—since this is for learning, I’ll break down the issues in your code and show you a more robust, idiomatic implementation step by step.
First, let's recap the code you shared (I’ll clean up the formatting a bit):
// Developed by Trofimov Yaroslav on 30.03.2018 #ifndef _ARRAY_H_TROFIMOV_ #define _ARRAY_H_TROFIMOV_ #include <string> template<const size_t n, typename T> class Array { static unsigned __freeId, __quantity; unsigned _id; T** _array; const size_t _n; public: typedef const bool (* const BooleanResultDelegate)(const T&...); // Your code cuts off here, but we can work with what's present };
Key Issues in Your Current Code
Let's go through the main problems that are likely causing you trouble:
Static Member Initialization
Template class static members (__freeIdand__quantity) need explicit initialization outside the class, and each template instantiation gets its own copy of these members. Your code doesn’t include this step, which will cause linker errors.Unnecessary & Risky Memory Management
UsingT** _arrayis overcomplicating things for a fixed-size array. A raw double pointer requires manual allocation of both the pointer array and each element, which is error-prone (easy to leak memory or mess up deallocation). For a fixed-size template array, we can use safer alternatives like smart pointers or even a built-in array.Const Member Initialization
Theconst size_t _nmember must be initialized in the constructor’s initialization list—you can’t assign to it later. Also, sincenis already a compile-time template parameter, storing it as a class member is redundant.Naming Conflicts
Names starting with double underscores (__freeId,__quantity) are reserved for the C++ standard library. Using them can lead to undefined behavior, so it’s best to avoid them.Redundant
constin Template Parameter
Non-type template parameters likesize_t nare already compile-time constants, so addingconsttoconst size_t nis unnecessary.
Revised Implementation
Here’s a fixed, modern C++ version of your Array template class, with explanations of each change:
// Developed by Trofimov Yaroslav on 30.03.2018 #ifndef ARRAY_H_TROFIMOV_ // Removed leading underscores to avoid reserved names #define ARRAY_H_TROFIMOV_ #include <iostream> #include <memory> // For smart pointers (safer memory management) #include <stdexcept> // For std::out_of_range template<size_t n, typename T> // Removed redundant const from template parameter class Array { static unsigned freeId; // Renamed to avoid double underscores static unsigned quantity; unsigned id; std::unique_ptr<T[]> array; // Use smart pointer to manage array memory automatically public: // Delegate type for boolean checks (completed your partial typedef) using BooleanResultDelegate = bool (*)(const T&); // Constructor: Initialize id, allocate array, track instance count Array() : id(freeId++), array(std::make_unique<T[]>(n)) { quantity++; } // Copy constructor: Perform deep copy to avoid shared memory issues Array(const Array& other) : id(freeId++), array(std::make_unique<T[]>(n)) { quantity++; // Copy each element from the original array for (size_t i = 0; i < n; ++i) { array[i] = other.array[i]; } } // Destructor: Smart pointer auto-releases memory; just decrement instance count ~Array() { quantity--; } // Overload [] for mutable element access (with bounds checking) T& operator[](size_t index) { if (index >= n) { throw std::out_of_range("Array index out of bounds"); } return array[index]; } // Overload [] for const element access const T& operator[](size_t index) const { if (index >= n) { throw std::out_of_range("Array index out of bounds"); } return array[index]; } // Get compile-time array size (constexpr for compile-time evaluation) constexpr size_t size() const { return n; } // Get instance ID unsigned getId() const { return id; } // Get total number of active Array instances static unsigned getQuantity() { return quantity; } // Example: Use the delegate to check if any element matches a condition bool findIf(BooleanResultDelegate predicate) const { for (size_t i = 0; i < n; ++i) { if (predicate(array[i])) { return true; } } return false; } }; // Initialize template static members (required for linker to find them) template<size_t n, typename T> unsigned Array<n, T>::freeId = 0; template<size_t n, typename T> unsigned Array<n, T>::quantity = 0; #endif // ARRAY_H_TROFIMOV_
How to Use the Revised Class
Here’s a quick test program to demonstrate how the class works:
#include "Array.h" #include <string> // Example predicate function for findIf bool isEven(int x) { return x % 2 == 0; } bool isLongerThanThree(const std::string& s) { return s.length() > 3; } int main() { // Create an array of 5 integers Array<5, int> intArr; intArr[0] = 1; intArr[1] = 2; intArr[2] = 3; intArr[3] = 4; std::cout << "intArr size: " << intArr.size() << "\n"; std::cout << "intArr[2]: " << intArr[2] << "\n"; std::cout << "Does intArr have an even number? " << std::boolalpha << intArr.findIf(isEven) << "\n"; // Create an array of 3 strings Array<3, std::string> strArr; strArr[0] = "Hi"; strArr[1] = "Hello"; strArr[2] = "Hey"; std::cout << "\nstrArr size: " << strArr.size() << "\n"; std::cout << "Does strArr have a long string? " << strArr.findIf(isLongerThanThree) << "\n"; // Check total active instances std::cout << "\nTotal Array instances: " << Array<5, int>::getQuantity() << " (int) + " << Array<3, std::string>::getQuantity() << " (string) = 2\n"; return 0; }
Key Takeaways for Learning
- Template Static Members: Always initialize them outside the class using template syntax.
- Smart Pointers: Prefer
std::unique_ptrorstd::shared_ptrover raw pointers to avoid memory leaks and simplify code. - Compile-Time Constants: Use template parameters for fixed sizes to let the compiler optimize your code.
- Bounds Checking: Adding checks to
operator[]prevents silent undefined behavior from out-of-bounds access.
内容的提问来源于stack exchange,提问作者ggghahaha

