如何把网站扒下来,营销型网站深度网,软件开发过程模型,怎么去掉一页wordpress每日一题
200. 岛屿数量
class Solution
{//使用深度的优先搜索来搜索岛屿图//遍历整个图片 当char数组的值为1时开始从这个点开始往外扩散搜索//注意处理边界 图不是正方形
public:int ans;int d[4][2] {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};int N;int M;void dfs(vectorint d[4][2] {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};int N;int M;void dfs(vectorvectorchar grid, vectorvectorint vis, int i, int j){for (int k 0; k 4; k){int nx i d[k][0];int ny j d[k][1];if (nx 0 || nx N - 1 || ny 0 || ny M - 1)continue;if (!vis[nx][ny] grid[nx][ny] ! 0){vis[nx][ny] 1;dfs(grid, vis, nx, ny);}}}int numIslands(vectorvectorchar grid){ans 0;N grid.size();M grid[0].size();vectorvectorint vis(N, vectorint(M, 0));for (int i 0; i N; i){for (int j 0; j M; j){if (!vis[i][j] grid[i][j] ! 0){ans;vis[i][j] 1;dfs(grid, vis, i, j);}}}return ans;}
};
C11新特性
自动类型推导auto 和 decltype 在C中自动类型推导是通过auto和decltype来实现的。这些关键字让程序员能够在不显式指定类型的情况下依赖编译器自动推导出变量的类型
auto:
auto关键字用于自动推导变量的类型。编译器根据初始化表达式的类型来推导变量的类型。它使得代码更加简洁尤其是在声明复杂类型如迭代器或lambda表达式时非常有用。使用示例 auto x 42; // x的类型是int
auto y 3.14; // y的类型是double
auto ptr new int(10); // ptr的类型是int*decltype:
decltype关键字用于推导一个表达式的类型但与auto不同的是decltype是在编译时对表达式类型的静态分析返回的是表达式的实际类型。它常用于模板编程或者当你想要获得某个表达式类型但又不确定时非常有用。使用示例 int x 42;
decltype(x) y 10; // y的类型是int与x相同右值引用和移动语义 右值引用和移动语义是C11引入的重要特性用来优化资源管理尤其是在处理动态分配内存、数组、容器等时避免不必要的深拷贝。
右值引用: 右值引用是通过符号表示的允许我们绑定到右值临时对象、即将销毁的对象上。 在传统的C中右值只能绑定到常量或临时变量但通过右值引用程序员可以显式地“转移”对象的所有权。 右值引用通常与移动语义一起使用使得对象的资源如内存、文件句柄等能够从一个对象转移到另一个对象而不是进行深拷贝。 使用示例 int r 10; // r是右值引用绑定到临时值10移动语义: 移动语义允许对象的资源如内存或文件句柄在不进行深拷贝的情况下从一个对象“移动”到另一个对象。 通过实现移动构造函数和移动赋值运算符C能够通过右值引用有效地转移资源而不是复制。 在标准库容器如std::vector、std::string中移动语义显著提高了性能因为容器可以直接将元素从一个容器转移到另一个容器而不需要复制每个元素。 使用示例 class MyClass {
public:MyClass(int size) : data(new int[size]) {}~MyClass() { delete[] data; }// 移动构造函数MyClass(MyClass other) noexcept : data(other.data) {other.data nullptr;}// 移动赋值运算符MyClass operator(MyClass other) noexcept {if (this ! other) {delete[] data;data other.data;other.data nullptr;}return *this;}private:int* data;
};详解等于号运算符重载实现移动语义
MyClass operator(MyClass other) noexcept {if (this ! other) {delete[] data; // 1data other.data; // 2other.data nullptr; // 3}return *this; // 4
}1. if (this ! other)
这行代码用来确保我们没有将一个对象赋值给它自己。我们需要避免以下的情况
obj1 std::move(obj1); // 这样就会发生自赋值如果this和other是相同的即它们指向的是同一个对象那么在移动操作时会导致对象的资源被错误地释放最终使得对象处于不一致的状态。因此首先通过这个条件判断来确保移动赋值操作不会出现自赋值的情况。
2. delete[] data;
这行代码释放当前对象的资源尤其是类中的动态分配内存data指针指向的内存。在进行移动赋值操作时我们必须释放当前对象的资源以便为从other对象“移动”资源做好准备。
为什么要释放资源
在“移动”资源之前我们需要确保当前对象没有持有相同的资源。假设data指向动态分配的内存在data other.data;之后data和other.data指向同一块内存。如果不释放原有的内存就会导致内存泄漏因为对象this和other都持有相同的资源指针但other指针的析构时会释放这块内存导致this的指针悬挂出现不一致的行为。
3. data other.data;
这行代码将other对象的data指针赋给当前对象data实现资源的“转移”。也就是说我们把other对象所管理的内存资源转移到当前对象this上。other.data指向原来的内存块而this-data也指向同一块内存块。
此时this对象就拥有了other对象的资源other对象中的data指针指向了同样的内存而other对象的资源将不再有效。
4. other.data nullptr;
在这行代码中我们将other.data指针置为nullptr。这是为了确保other对象在析构时不会试图释放资源。由于我们已经将other对象的资源转移给了thisother对象不再拥有该资源因此将other.data置为nullptr可以防止其析构时错误地删除内存。
这一步是移动操作的核心确保在移动后other对象不会误操作原本应该由this对象管理的内存避免多次释放同一块内存。
5. return *this;
最后返回*this即当前对象的引用。这是符合赋值运算符规范的做法返回*this允许链式赋值操作例如
a b c;这里a b c;首先执行b c;然后执行a b;每次都会返回赋值后的对象以便进行下一次赋值。
为什么使用noexcept
noexcept关键字表示这个移动赋值运算符不抛出任何异常。移动操作通常不需要动态分配内存或者执行复杂的操作因此它应该是一个不会抛出异常的操作。如果移动赋值操作抛出异常则会破坏对象状态的一致性并导致潜在的问题。