Arrays in C ++


Wir setzen die Serie „C ++, tiefer graben“ fort. Der Zweck dieser Serie ist es, Ihnen so viel wie möglich über die verschiedenen Merkmale der Sprache zu erzählen, möglicherweise ganz besonders. Dies ist der vierte Artikel in der Reihe, die ersten drei zum Überladen in C ++ sind hier , hier und hier .

Dieser Artikel handelt von Arrays. Arrays können den ältesten Schichten von C ++ zugeordnet werden, sie stammen aus den ersten Versionen von C. Trotzdem sind Arrays im objektorientierten Typsystem von C ++ enthalten, wenn auch mit einigen Einschränkungen. Für den Programmierer ist es wichtig, diese Funktionen zu kennen, um mögliche Fehler zu vermeiden. Der Artikel untersucht auch ein anderes C-Erbe - triviale Typen und nicht initialisierte Variablen. Einige der Innovationen von C ++ 11 wirken sich auf die Arbeit mit Arrays aus. Alle diese neuen Funktionen werden ebenfalls ausführlich beschrieben. Versuchen wir also, alles über Arrays zu erzählen.



Inhaltsverzeichnis


Inhaltsverzeichnis

  1.
    1.1.
    1.2.
    1.3.
    1.4.
  2.
    2.1.
    2.2.
  3.
    3.1.
    3.2.
      3.2.1
      3.2.2
      3.2.3
  4.
    4.1.
    4.2.
  5.
  6.
    6.1.
    6.2.
    6.3.
  7.
  8.
  




1. Allgemeine Bestimmungen


Ein Array ist der einfachste Aggregattyp. Er modelliert eine Reihe ähnlicher Elemente, die in einem fortlaufenden Speichersegment in einer Reihe angeordnet sind. Arrays in der einen oder anderen Form werden von fast allen Programmiersprachen unterstützt, und es ist nicht überraschend, dass sie in den ersten Versionen von C erschienen und dann Teil von C ++ wurden.



1.1. Array-Deklaration


Wenn Tein Typ, eine NKonstante oder ein Ausdruck zur Kompilierungszeit ausgewertet wird, dann die Anweisung


T a[N];

a « N T» (array of N elements of the type T). N std::size_t, , , . sizeof(T) , , , N*sizeof(T) . . T[N], . , , , , .


(regular arrays), , «» C++ .

:


const int N = 8;
constexpr int Square(int n) { return n * n; }

int a1[1];
int a2[N];
int a3['Q'];
int a4[Square(2)];

:


int n;

int b1[0];   //  
int b2[n];   //      
int b3["Q"]; //     size_t

, 0 N-1. :


int a[4];
a[0] = 42;
int t = a[3];

, .


, .


int a[4], b[8];

. typedef:


typedef int I4[4];

(C++11) using:


using I4 = int[4];

:


I4 a, b;

,


int a[4], b[4];


1.2.


sizeof .


sizeof , .


_countof() ( MSVS <cstdlib>) , . ++17 std::size(), ( , ).


int a[4];
std::cout << sizeof(a) << ' ' << std::size(a) << '\n';

: 16 4


C++11 ( ) std::begin() std::end(). std::begin() , std::end() past-the-last . ( : std::cbegin(), std::cend().) for.


int a[4]{ 4, 3, 2, 1 };

for (auto t : a)
{
    std::cout << t << ' ';
}

:


std::sort(std::begin(a), std::end(a));


1.3.


, , , . , , . (, .) . (. 6) .



1.4.


, void.


.


int u, v;
int &rr[2] = { u, v }; // 

.


int * const rr[2] = { &u, &v };

( 3.2.)


C++11 std::reference_wrapper<>. , . , - get(). .


int u = 42, v = 5;
std::reference_wrapper<int> rr[2] = { u, v };
std::cout << rr[0] << ' ' << rr[1] << '\n'; // : 42 5
++rr[0];
rr[1].get() = 125;                          // get() 
std::cout << u << ' ' << v << '\n';         // : 43 125

.


int ff[2](double); // 

.


int (*ff[2])(double);

std::reference_wrapper<> , — , &. — std::function<>, .


auto.


auto x[2] = {1, 2}   // 

const , .


using I4 = int[4];
const I4 ci; //  ,   const int ci[4];


2.


, C++.



2.1.


, , «». (decay, array-to-pointer decay). (Decay .) , . sizeof, & ( ) . sizeof 1.2, 4. decltype , .


, . ( C) :


const int N = 100;
int a[N];
for (int *d = a, *end = d + N; d < end; ++d)
{
    *d = rand();
}

, .


.


void Foo(int a[4]);
void Foo(int a[]);
void Foo(int *a);

— . (, ).


.


// file 1
int A[4];

// file 2
extern int A[];

.


auto .


int a[4];
auto da = a; //  da   int*



template<typename T>
void Foo(T t);

, .


. ( C .) .


class B {/* ... */};
class D : public B {/* ... */};
void Foo(B[], int size); //     B

.


D d[4];
Foo(d, _countof(d));

sizeof(B) < sizeof(D), Foo() d ( , ) , , Foo() . , , .



2.2.


( ) , «». , :


using I4 = int[4];
I4 a;
I4 b = a; // 
I4 b2;
b2 = a; // 

.


I4 Foo(); // 

//, ( ) .


struct X 
{ 
    int A[4]; 
};

, .


X Foo();
X x;
X x2 = x;
X x3;
x3 = Foo();


3.


.



3.1.


++. , — . , . , . , ++, . , , , , , , . : , , , , .


, - . . , . , - , .


: (), , , , . , . .


, , .


++11 , ( <type_traits>). , . std::is_trivial<>::value true, T false .



3.2.



3.2.1.


, . , , . , , .


C :


int a[4] = { 1, 2, 3, 4 };

++11 (uniform initialization) :


int a[4]{ 1, 2, 3, 4 };

=, , , , .


, .


int a[] { 1, 2, 3, 4 };

, . , (, , ), . , , .


int a[4]{};

.


const int a[4] = { 3, 2, 1 };

, .


.


const char str[] = "meow";
const wchar_t wstr[] = L"meow";

, .


3.2.2.


++11 , . : .


class X
{
    int a[4]{ 1, 2, 3, 4 };
    int b[2];
// ...
public:
    X(int u, int v) : b{ u, v } 
    {}
// ...
};

, .


, , , .


class X
{
    static int A[];
// ...
};

int X::A[] = { 1, 2, 3, 4 };


3.2.3.


, , , (, , constexpr). , , — . :


T a[] = {x1 /*, ... */};



T a[]{x1 /*, ... */};



T t = x1;

. .


.


class Int
{
    int m_Value;
public:
    Int(int v) : m_Value(v) {}
// ...
};
// ...
int x, y;
// ...
Int rr[] = { x, y };

Int explicit, .


Int rr[] = { Int(x), Int(y) };

. .



4.



4.1.




T a[N];

:


T(*pa)[N] = &a;

&. T(*)[N].


, N T.


— ( , , ), . , «» . .


int a[4];
int(*pa)[4] = &a; // OK
int(*p2)[2] = &a; // ,   

, .


* .


(*pa)[3] = 42;

.


using I4 = int[4];
I4 a{ 1, 2, 3, 4 };
I4 *pa = &a;

auto, .


int a[4];
auto pa = &a; //  pa   int(*)[4]

, .



4.2.




T a[N];

:


T(&ra)[N] = a;

, . T(&)[N].


.


T(*pa)[N] = &a;
T(&ra)[N] = *pa;

, «» . .


int a[4];
int(&ra)[4] = a; // OK
int(&r2)[2] = a; // ,   

, .


ra[3] = 0;

, .




void Foo(T(&a)[N]);

T[N], .


.


using I4 = int[4];
I4 a{ 1, 2, 3, 4 };
I4 &ra = a;

auto, .


int a[4];
auto &ra = a; //  ra   int(&)[4]

& auto, , ra int*.




template<typename T>
void Foo(T& t);

, .


.


template<typename T, std::size_t N>
void Foo(T(&a)[N]);

T N ( ). , . _countof() std::size(), std::begin() std::end(), for . 5 .



5.


C++ , a[N, M] , « », a[N][M].


T , N M , ,


T a[N][M];

a , N , M T. . a[i][j], i 0 N-1, j 0 M-1, . , . N , M . T[N][M].


a[i] M T. , .


T *dai = a[i];
T(*pai)[M] = &a[i];
T(&rai)[M] = a[i];

. , .


T a[N][M];
T(*da)[M] = a;

, :


void Foo(T a[N][M]);
void Foo(T a[][M]);
void Foo(T(*a)[M]);

, .


.


using I4 = int[4];
I4 b[2];

,


int b[2][4];

:


int b[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};

, {}. .


int b[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; // 
int b[][] = {{1, 2, 3, 4}, {5, 6, 7, 8}};  // 

:


T a[N][M];
T(*pa)[N][M] = &a;

. .


template<typename T, std::size_t N, std::size_t M>
void Print2dArray(T(&a)[N][M])
{
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < M; ++j)
        {
            std::cout << a[i][j] << ' ';
        }
        std::cout << '\n';
    }
}
// ...
int b[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
Print2dArray(b);

:


1 2 3 4
5 6 7 8

.


T mtx[N][M];

N , M , mtx[i][j] i- j- , mtx[i] M, i- . , . , .



6.


C++ « ». , ( ). . C++ .



6.1.


T , n , ,


T *pa = new T[n];

. n std::size_t, . , , n*sizeof(T), . pa .


T , , .


C++11 .


int *pa = new int[n]{1, 2, 3, 4};

, ( , n ). , , . , , .


new[] . , , T , . - , , , . std::bad_alloc.


delete[], , new[].


delete[] pa;

, , , ( ), .


pa, new[], , ( «») , . for.



6.2.


std::unique_ptr<> (. [Josuttis]). , [] -> delete[] . :


int n = 100; 
std::unique_ptr<int[]> aptr(new int[n]);
for (int i = 0; i < n; ++i)
{
    aptr[i] = i; 
}

: , , for. std::unique_ptr<> , std::vector<>. std::shared_ptr<> .



6.3.


, new T[n][m], n m , . , , . M , , :


T(*pa)[M] = new T[n][M];

new[] . pa[i][j], pa[i] M T.


.


using I4 = int[4];
I4 *pa = new I4[n];

[] , , . .


// 2D interface to a buffer
template<typename T>
class MatrixView 
{
    T * const m_Buff;
    int const m_RowCount;
    int const m_ColCount;
public:
    MatrixView(T* buff, int rowCount, int colCount)
        : m_Buff(buff)
        , m_RowCount(rowCount)
        , m_ColCount(colCount)
    {}
    T *operator[](int rowInd) const
    {
        return m_Buff + rowInd * m_ColCount;
    }
};
// buffer owner
template<typename T>
class DynBuffer 
{
    T* const m_Buff;
protected:
    T* Buff() const { return m_Buff; };
    DynBuffer(int length) : m_Buff(new T[length]{}) {}
    ~DynBuffer() { delete[] m_Buff; }
    DynBuffer(const DynBuffer&) = delete;
    DynBuffer& operator=(const DynBuffer&) = delete;
};

template<typename T>
class MatrixSimple 
    : DynBuffer<T>, public MatrixView<T>
{
    using Buff = DynBuffer<T>;
    using View = MatrixView<T>;
public:
    MatrixSimple(int rowCount, int colCount)
        : Buff(rowCount * colCount)
        , View(Buff::Buff(), rowCount, colCount)
    {}
};

:


MatrixSimple<int> mtx(3, 3);
mtx[1][2] = 42; //  ,  

proxy-, , RowProxy, . , , , - begin(), end(), etc. .



7.


, «». T[]. .


//  
template <typename T>
class U
{
public:
    const char* Tag() const { return "base"; }
};

//    
template <typename T>
class U<T*>
{
public:
    const char* Tag() const { return "pointer"; }
};

//    
template <typename T>
class U<T[]>
{
public:
    const char* Tag() const { return "array"; }
};

U<int> u1;
U<int*> u2;
U<int[]> u3;

std::cout << u1.Tag() << ' ' << u2.Tag() << ' ' << u3.Tag();

: base pointer array


std::unique_ptr<>, , . 6.2.



8.


( ), .


std::array<>. ( C++11, . [Josuttis].) , : . , . :


std::array<int, 4> a{1, 2, 3, 4};

.


for (int i = 0; i < a.size(); ++i)
{
    std::cout << a[i] << ' ';
}
for (auto it = a.begin(); it != a.end(); ++it)
{
    std::cout << *it << ' ';
}
for (auto t : a)
{
    std::cout << t << ' ';
}

std::vector<>. , ( №1), - .


std::valarray<>. .




[Josuttis]
Josattis, Nikolai M. C ++ - Standardbibliothek: Referenzhandbuch, 2. Ausgabe: Per. aus dem Englischen - M.: LLC “I.D. Williams, 2014.




All Articles