Continuamos a série "C ++, aprofundando". O objetivo desta série é informar o máximo possível sobre os vários recursos do idioma, possivelmente bastante especiais. Este é o quarto artigo da série, os três primeiros sobre sobrecarga em C ++ estão aqui , aqui e aqui .
Este artigo é sobre matrizes. As matrizes podem ser atribuídas às camadas mais antigas do C ++, elas vieram das primeiras versões do C. No entanto, as matrizes são incluídas no sistema de tipo orientado a objetos do C ++, embora com algumas ressalvas. É importante que o programador conheça esses recursos para evitar possíveis erros. O artigo também explora outro legado em C - tipos triviais e variáveis não inicializadas. Algumas das inovações do C ++ 11 afetam o trabalho com matrizes; todos esses novos recursos também são descritos em detalhes. Então, vamos tentar contar tudo sobre matrizes.
Índice
1. Disposições Gerais
Uma matriz é o tipo agregado mais simples. Ele modela um conjunto de elementos semelhantes organizados em uma linha em um segmento contínuo de memória. Matrizes de uma forma ou de outra são suportadas por quase todas as linguagens de programação e não surpreende que elas tenham aparecido nas primeiras versões do C e depois tenham se tornado parte do C ++.
1.1 Declaração de matriz
Se T
algum tipo, N
constante ou expressão for avaliada em tempo de compilação, a instrução
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"];
, 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';
++rr[0];
rr[1].get() = 125;
std::cout << u << ' ' << v << '\n';
.
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;
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);
— . (, ).
.
int A[4];
extern int A[];
.
auto
.
int a[4];
auto da = a;
template<typename T>
void Foo(T t);
, .
. ( C .) .
class B {};
class D : public B {};
void Foo(B[], int size);
.
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;
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;
, .
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;
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;
&
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];
[]
, , . .
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;
}
};
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 padrão C ++: Guia de Referência, 2ª ed.: Per. do inglês - M .: LLC “I.D. Williams, 2014.