C++ 常函数、迭代器、NULL 和 nullptr、构造函数、delete 和 delete[]、extern 关键字详解
'C++ 中常函数指的是在类的成员函数声明中使用 const 关键字的函数,表示该函数不会修改对象的状态。常函数的特点包括:
-
常函数不能修改对象的数据成员,包括非 const 和 mutable 成员变量。这也是常函数的主要作用之一,保证对象状态的不变性。
-
常函数可以被常对象调用,也可以被非常对象调用。但是,非常对象调用常函数时,常函数内部不能修改对象的状态。
-
常函数可以被重载,例如可以定义常函数和非常函数版本的同名函数。这样可以实现函数的多态性。
-
常函数可以返回常量值或常量引用,例如可以定义一个常函数返回对象的常量成员变量。
-
常函数的定义和声明必须同时使用 const 关键字,否则会编译错误。常函数的定义和声明也必须保持一致,否则会链接错误。'
'如果想在常函数中修改成员变量,可以将该成员变量声明为 mutable 类型。mutable 关键字可以修饰成员变量,表示该成员变量可以在常函数中被修改。但是需要注意的是,由于常函数的本质是不允许修改对象状态,因此在使用 mutable 关键字时需要慎重考虑,确保修改的行为不会影响对象的状态。'
'C++ 中的迭代器是用来遍历容器中的元素的工具。它提供了一种统一的访问容器元素的方法,可以像指针一样对容器中的元素进行访问。通过迭代器,可以实现对容器元素的遍历、查找、修改等操作,从而简化了对容器的操作。C++ 标准库中提供了多种类型的迭代器,包括正向迭代器、反向迭代器、随机访问迭代器等,不同类型的迭代器支持不同的操作。使用迭代器可以使代码更加简洁、高效、安全。'
'栈和优先级队列不支持迭代器。栈是一种后进先出的数据结构,只能从栈顶进行访问和操作,因此不需要迭代器。同样,优先级队列是一种按照优先级排序的容器,只能访问和操作优先级最高的元素,也不需要迭代器。不过,栈和优先级队列在实现上都可以使用迭代器的概念,例如栈可以通过指针来实现迭代器的功能,优先级队列可以使用指针或者迭代器来实现对元素的访问。但是,这些实现方式并不是标准库提供的,也不是常用的操作方式。'
'是的,迭代器是 STL 中容器和算法之间的桥梁,它提供了一种统一的访问容器元素的方法,使得算法可以独立于容器而运作。通过迭代器,STL 中的算法可以对不同类型的容器进行遍历、查找、排序、复制等操作,从而增强了算法的可复用性和通用性。迭代器的设计和实现是 STL 的重要组成部分,也是 STL 成功的关键之一。'
'在 C++ 中,STL 中的迭代器失效是指指向容器元素的迭代器不再指向原来的元素,而是指向了其他元素或已经失效,这会导致程序出现未定义行为,例如访问非法内存,引发崩溃等问题。迭代器失效的原因通常是由于容器的操作导致元素的位置发生变化,例如插入、删除元素等操作都可能会导致迭代器失效。
具体来说,以下情况可能导致迭代器失效:
-
在容器中插入或删除元素,会导致迭代器失效。
-
在容器中进行排序、合并等操作,可能会导致迭代器失效。
-
在容器中进行重分配内存的操作,例如 vector 的 push_back 操作,也可能会导致迭代器失效。
为了避免迭代器失效的问题,可以采用以下方法:
-
尽量避免在循环中对容器进行插入或删除操作,可以先将要修改的元素保存在一个临时容器中,待循环结束后再进行操作。
-
在进行容器操作之前,可以先将迭代器保存在一个临时变量中,在操作完成后再重新获取迭代器。
-
使用 STL 中提供的安全的算法和容器操作,例如使用 std::copy 算法代替手动遍历容器进行元素拷贝。'
'C 语言中的 NULL 是一个宏定义,表示空指针常量,通常定义为 0。在 C++11 标准中,引入了 nullptr 关键字,表示空指针常量,与整数 0 区别开来。nullptr 是一个关键字,具有类型 std::nullptr_t,可以隐式转换为指针类型,而 NULL 则不具有类型信息,可能会在一些类型安全的场合出现问题。因此,建议在 C++ 中使用 nullptr 代替 NULL,以提高程序的可读性和类型安全性。'
'构造函数是一种特殊的成员函数,用于在创建对象时对对象进行初始化。它的名称与类名相同,没有返回类型,可以有参数,也可以没有参数。在对象创建时,构造函数会自动调用,执行对象的初始化操作。
构造函数的作用包括:
-
对象的初始化:构造函数可以对对象的数据成员进行初始化,确保对象在创建时处于一个合法的状态。
-
分配资源:构造函数可以分配对象所需要的资源,例如内存、文件句柄等。
-
执行验证操作:构造函数可以执行一些验证操作,例如检查输入参数是否合法,确保对象的不变量成立等。
-
实现多态性:构造函数可以被重载,即可以定义多个同名的构造函数,用于初始化不同的对象。这样就可以实现构造函数的多态性,提高程序的灵活性和可扩展性。'
'在 C++ 中,delete 和 delete[] 都是用于释放动态分配的内存空间的运算符,但是它们之间存在一些区别。
-
delete 用于释放通过 new 运算符分配的单个对象的内存空间,而 delete[] 用于释放通过 new[] 运算符分配的数组对象的内存空间。
-
delete 和 delete[] 的语法不同,delete 只需要一个指针作为参数,而 delete[] 需要一个数组指针作为参数。
-
delete 和 delete[] 释放内存的方式不同,delete 只释放指向的对象的内存空间,而 delete[] 会释放整个数组的内存空间,包括每个元素的空间和数组的控制信息。
-
如果使用 delete[] 释放通过 new 运算符分配的单个对象的内存空间,或者使用 delete 释放通过 new[] 运算符分配的数组对象的内存空间,都会导致未定义行为,可能会引发内存泄漏或者程序崩溃的问题。
因此,在使用 delete 和 delete[] 时,需要根据动态分配的对象的类型选择合适的运算符,并且保证所释放的内存空间与分配的内存空间类型和数量匹配。同时,为了避免内存泄漏和指针悬挂等问题,建议在释放内存空间之前将指针赋值为 nullptr。'
'extern 关键字用于声明外部变量或函数,表示该变量或函数是在其他文件中定义的,并且可以在当前文件中使用。extern 关键字可以用于以下情况:
-
声明全局变量:如果想在一个文件中定义全局变量,然后在另一个文件中使用该变量,可以在使用变量的文件中使用 extern 关键字来声明该变量。
-
声明全局函数:如果想在一个文件中定义全局函数,然后在另一个文件中使用该函数,可以在使用函数的文件中使用 extern 关键字来声明该函数。
-
声明类成员函数:如果想在一个类的定义中声明成员函数,但是不想在类定义中进行函数的实现,可以在类定义中使用 extern 关键字声明该函数,然后在类外部进行函数的实现。
使用 extern 关键字可以实现多个文件之间的变量和函数共享,避免了重复定义和声明的问题,提高了程序的可维护性和可扩展性。'
原文地址: https://www.cveoy.top/t/topic/ouMI 著作权归作者所有。请勿转载和采集!