我们这里不做 C ......请使用比 M 和 N 更多字母的标识符。
#include <cstddef>
#include <iostream>
#include <algorithm>
#include <numeric>
#include <iterator>
template<typename T, std::size_t ROWS, std::size_t COLS>
void print_arr(T (&arr)[COLS][ROWS])
{
for (size_t row{}; row < ROWS; ++row) {
std::copy(&arr[row][0], &arr[row][0] + COLS,
std::ostream_iterator<T>{ std::cout, "\t" });
std::cout.put('\n');
}
std::cout.put('\n');
}
template<typename T, std::size_t ROWS, std::size_t COLS>
void kill_all_from_line_till_last(T (&arr)[COLS][ROWS], std::size_t kill_from)
{
std::fill(&arr[kill_from][0], &arr[kill_from][0] + (ROWS - kill_from) * COLS, T{});
}
int main()
{
constexpr size_t rows { 10 };
constexpr size_t columns { 10 };
int arr[rows][columns];
std::iota(&arr[0][0], &arr[0][0] + columns * rows, 1);
print_arr(arr);
kill_all_from_line_till_last(arr, 7);
print_arr(arr);
}
输出:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
伪 C 版本:
...使用std::memset() 看起来几乎一样:
#include <cstring>
template<typename T, std::size_t ROWS, std::size_t COLS>
void kill_all_from_line_till_last(T (&arr)[COLS][ROWS], std::size_t kill_from)
{
std::memset(&arr[kill_from][0], 0, (ROWS - kill_from) * COLS * sizeof(T));
}
但您只能将其用于 POD。
速度:
既然您提到您发现与std::memset() 相比,std::fill() 对于您的需求来说太慢了
@搜楚:
使用填充,可以,但是太慢了。我想要memset
constexpr size_t rows { 10 };
constexpr size_t columns { 10 };
{
int arr[rows][columns];
std::iota(&arr[0][0], &arr[0][0] + columns * rows, 1);
print_arr(arr);
kill_all_from_line_till_last_fill(arr, 7);
print_arr(arr);
}
{
int arr[rows][columns];
std::iota(&arr[0][0], &arr[0][0] + columns * rows, 1);
print_arr(arr);
kill_all_from_line_till_last_memset(arr, 7);
print_arr(arr);
}
gcc
从 gcc 9.1 (--std=c++14 -O3 -Wall) 组装:
; ...
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
xor eax, eax
mov ecx, 15
mov rdi, rbx
rep stosq
mov rdi, rsp
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
; ...
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
xor eax, eax
mov rdi, rbx
mov ecx, 15
rep stosq
mov rdi, rsp
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
; ...
正如您所见,这两个版本在调用print_arr() 之间生成完全相同的代码。编译器并不(那么)愚蠢。
完整代码:godbolt Compiler Explorer
叮当
clang 8.3.0 (--std=c++14 -Ofast3 -Wall) 相同,std::fill() 和 std::memset() 的代码完全相同:
; ...
mov rdi, rbx
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
xorps xmm0, xmm0
movups xmmword ptr [rsp + 376], xmm0
movups xmmword ptr [rsp + 360], xmm0
movups xmmword ptr [rsp + 344], xmm0
movups xmmword ptr [rsp + 328], xmm0
movups xmmword ptr [rsp + 312], xmm0
movups xmmword ptr [rsp + 296], xmm0
movups xmmword ptr [rsp + 280], xmm0
mov qword ptr [rsp + 392], 0
mov rdi, rbx
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
; ...
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
xorps xmm0, xmm0
movups xmmword ptr [rsp + 376], xmm0
movups xmmword ptr [rsp + 360], xmm0
movups xmmword ptr [rsp + 344], xmm0
movups xmmword ptr [rsp + 328], xmm0
movups xmmword ptr [rsp + 312], xmm0
movups xmmword ptr [rsp + 296], xmm0
movups xmmword ptr [rsp + 280], xmm0
mov qword ptr [rsp + 392], 0
mov rdi, rbx
call void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
; ...
完整代码:godbolt Compiler Explorer
msvc
微软 cl 19.20 (/O2):
; ...
call void print_arr<int,10,10>(int (&)[10][10])
xorps xmm0, xmm0
lea rcx, QWORD PTR arr$2[rsp]
xor eax, eax
movups XMMWORD PTR arr$2[rsp+280], xmm0
mov QWORD PTR arr$2[rsp+392], rax
movups XMMWORD PTR arr$2[rsp+296], xmm0
movups XMMWORD PTR arr$2[rsp+312], xmm0
movups XMMWORD PTR arr$2[rsp+328], xmm0
movups XMMWORD PTR arr$2[rsp+344], xmm0
movups XMMWORD PTR arr$2[rsp+360], xmm0
movups XMMWORD PTR arr$2[rsp+376], xmm0
call void print_arr<int,10,10>(int (&)[10][10]) ;
; ...
call void print_arr<int,10,10>(int (&)[10][10])
xorps xmm0, xmm0
lea rcx, QWORD PTR arr$1[rsp]
xor eax, eax
movups XMMWORD PTR arr$1[rsp+280], xmm0
mov QWORD PTR arr$1[rsp+392], rax
movups XMMWORD PTR arr$1[rsp+296], xmm0
movups XMMWORD PTR arr$1[rsp+312], xmm0
movups XMMWORD PTR arr$1[rsp+328], xmm0
movups XMMWORD PTR arr$1[rsp+344], xmm0
movups XMMWORD PTR arr$1[rsp+360], xmm0
movups XMMWORD PTR arr$1[rsp+376], xmm0
call void print_arr<int,10,10>(int (&)[10][10])
; ...
完整代码:godbolt Compiler Explorer
我认为实验可以到此结束。