Matrices en C ++


Continuamos la serie "C ++, cavando más profundo". El propósito de esta serie es informarle lo más posible sobre las diversas características del lenguaje, posiblemente bastante especial. Este es el cuarto artículo de la serie, los primeros tres sobre sobrecarga en C ++ están aquí , aquí y aquí .

Este artículo es sobre matrices. Las matrices se pueden atribuir a las capas más antiguas de C ++, vinieron de las primeras versiones de C. Sin embargo, las matrices se incluyeron en el sistema de tipo orientado a objetos de C ++, aunque con ciertas reservas. Es importante que el programador conozca estas características para evitar posibles errores. El artículo también explora otro legado de C: tipos triviales y variables no inicializadas. Algunas de las innovaciones de C ++ 11 afectan el trabajo con matrices; todas estas nuevas características también se describen en detalle. Entonces, intentemos contar todo sobre las matrices.



Tabla de contenido


Tabla de contenido

  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. Disposiciones generales


Una matriz es el tipo agregado más simple. Él modela un conjunto de elementos similares dispuestos en una fila en un segmento continuo de memoria. Las matrices de una forma u otra son compatibles con casi todos los lenguajes de programación, y no es sorprendente que aparecieran en las primeras versiones de C y luego se convirtieran en parte de C ++.



1.1. Declaración de matriz


Si Talgún tipo, Nconstante o expresión evaluada en tiempo de compilación, entonces la instrucción


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. Biblioteca estándar de C ++: Guía de referencia, 2ª ed .: Per. De inglés - M .: LLC "I.D. Williams, 2014.




All Articles