const_cast
- **作用**:用于去除指针或引用的`const`或`volatile`限定符。
- **示例代码**:
#include
void func(const int* ptr) {
// 错误,不能直接修改const指针指向的值
// *ptr = 10;
int* nonConstPtr = const_cast<int*>(ptr);
*nonConstPtr = 10;
}
int main() {
int num = 5;
const int* constPtr = #
std::cout << "Before func, num = " << num << std::endl;
func(constPtr);
std::cout << "After func, num = " << num << std::endl;
return 0;
}
- **使用场景**:当你确定某个对象不会因为修改而导致问题,
- 但函数参数或返回值是`const`限定的,需要临时去除`const`来进行修改时使用。
- 不过,滥用`const_cast`可能会导致程序出现未定义行为,所以要谨慎使用。
static_cast
- **作用**:用于在相关类型之间进行转换,例如基本数据类型转换、类层次结构中的向上转换(将派生类指针或引用转换为基类指针或引用)。
- **示例代码(基本数据类型转换)**:
#include
int main() {
double numDouble = 3.14;
int numInt = static_cast<int>(numDouble);
std::cout << "Converted value: " << numInt << std::endl;
return 0;
}
- **示例代码(类层次结构向上转换)**:
#include
class Base {
public:
virtual void print() {
std::cout << "This is Base class." << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << "This is Derived class." << std::endl;
}
};
int main() {
Derived derivedObj;
Base* basePtr = static_cast<Base*>(&derivedObj);
basePtr->print();
return 0;
}
- **使用场景**:在已知类型之间安全地进行转换,如将一种算术类型转换为另一种算术类型,或者在类层次结构中进行向上转换(当派生类对象的行为可以被基类行为所包含时)。
dynamic_cast
- **作用**:主要用于在类层次结构中的向下转换(将基类指针或引用转换为派生类指针或引用),并且在运行时进行类型检查。
#include
class Base {
public:
virtual void print() {
std::cout << "This is Base class." << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << "This is Derived class." << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
// 进行动态转换
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
derivedPtr->print();
} else {
std::cout << "Dynamic cast failed." << std::endl;
}
delete basePtr;
return 0;
}
- **使用场景**:当你有一个指向基类的指针或引用,并且不确定它实际指向的是哪个派生类对象,需要在运行时进行检查并进行向下转换时使用。这在处理多态对象时非常有用,例如在一个图形绘制系统中,根据不同的图形类型(圆形、矩形等派生类)进行不同的绘制操作。
reinterpret_cast
- **作用**:可以进行几乎任意类型之间的转换,包括一些在语义上不相关的类型转换,它只是简单地重新解释二进制数据。
#include
int main() {
int num = 10;
// 将int*转换为char*,这只是重新解释内存布局
char* charPtr = reinterpret_cast<char*>(&num);
std::cout << "Memory representation as characters: ";
for (int i = 0; i < sizeof(int); ++i) {
std::cout << charPtr[i];
}
std::cout << std::endl;
return 0;
}
- **使用场景**:在一些非常底层的操作中,如与硬件接口或者处理二进制数据格式时使用。不过,这种转换很危险,因为它可能会导致不可预测的结果,除非你非常清楚自己在做什么。
auto_ptr
(已弃用)-示例代码(不推荐使用):
#include
#include
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor called." << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor called." << std::endl;
}
void printMessage() {
std::cout << "This is a message from MyClass." << std::endl;
}
};
int main() {
std::auto_ptr<MyClass> autoPtr(new MyClass);
autoPtr->printMessage();
// 注意:auto_ptr存在所有权转移问题,不推荐使用
return 0;
}
- **使用场景(已不推荐)**:`auto_ptr`曾经用于自动管理动态分配的对象的内存,但它有一个严重的问题,
- 即当进行复制操作时会转移所有权,这可能导致意外的行为。
- 现在已经被`unique_ptr`等更好的智能指针所替代。
shared_ptr
#include
#include
class AnotherClass {
public:
AnotherClass() {
std::cout << "AnotherClass constructor called." << std::endl;
}
~AnotherClass() {
std::cout << "AnotherClass destructor called." << std::endl;
}
void showMessage() {
std::cout << "This is a message from AnotherClass." << std::endl;
}
};
int main() {
std::shared_ptr<AnotherClass> sharedPtr1(new AnotherClass);
std::shared_ptr<AnotherClass> sharedPtr2 = sharedPtr1;
// 引用计数为2
sharedPtr1->showMessage();
sharedPtr2->showMessage();
// 当最后一个指向该对象的shared_ptr离开作用域时,对象才会被销毁
return 0;
}
shared_ptr
引用这个对象,它就不会被销毁,直到所有引用都消失。比如在一个缓存系统中,多个用户可能同时访问和使用同一个缓存对象,就可以用shared_ptr
来管理这个缓存对象的内存。引用计数的线程安全
原理:std::shared_ptr的引用计数操作本身是原子操作(在标准库的实现中),这意味着多个线程同时对std::shared_ptr进行拷贝构造或者赋值操作(这些操作会改变引用计数)是安全的。
示例代码:
#include
#include
#include
#include
void func(std::shared_ptr<int> ptr) {
// 多个线程同时访问这个函数,对shared_ptr进行拷贝
// 引用计数的原子操作保证线程安全
std::shared_ptr<int> localPtr = ptr;
std::cout << "Thread " << std::this_thread::get_id() << " - Reference count: " << localPtr.use_count() << std::endl;
}
int main() {
std::shared_ptr<int> sharedPtr(new int(10));
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i) {
threads.push_back(std::thread(func, sharedPtr));
}
for (auto& th : threads) {
th.join();
}
return 0;
}
示例代码:
#include
#include
#include
#include
class Counter {
public:
Counter() : count(0) {}
void increment() {
std::lock_guard<std::mutex> guard(mutex_);
++count;
}
int getCount() const {
std::lock_guard<std::mutex> guard(mutex_);
return count;
}
private:
mutable std::mutex mutex_;
int count;
};
void threadFunction(std::shared_ptr<Counter> counter) {
for (int i = 0; i < 1000; ++i) {
counter->increment();
}
}
int main() {
std::shared_ptr<Counter> sharedCounter(new Counter);
std::thread thread1(threadFunction, sharedCounter);
std::thread thread2(threadFunction, sharedCounter);
thread1.join();
thread2.join();
std::cout << "Final count: " << sharedCounter->getCount() << std::endl;
return 0;
}
weak_ptr
shared_ptr
配合):#include
#include
class Node {
public:
std::shared_ptr<Node> next;
int data;
Node(int d) : data(d) {}
};
int main() {
std::shared_ptr<Node> node1(new Node(1));
std::shared_ptr<Node> node2(new Node(2));
node1->next = node2;
std::weak_ptr<Node> weakNode = node1;
if (std::shared_ptr<Node> lockedNode = weakNode.lock()) {
std::cout << "The node data is: " << lockedNode->data << std::endl;
} else {
std::cout << "The node has been destroyed." << std::endl;
}
node1.reset();
node2.reset();
if (std::shared_ptr<Node> lockedNode = weakNode.lock()) {
std::cout << "The node data is: " << lockedNode->data << std::endl;
} else {
std::cout << "The node has been destroyed." << std::endl;
}
return 0;
}
shared_ptr
的循环引用问题。在上述链表的例子中,如果没有weak_ptr
,当两个节点相互引用(例如双向链表)且都用shared_ptr
时,它们的引用计数永远不会为0,导致内存泄漏。weak_ptr
可以用来观察shared_ptr
所指向的对象,而不会增加引用计数,从而打破循环引用。#include
#include
#include
void threadFunction(std::weak_ptr<int> weakPtr) {
std::shared_ptr<int> sharedPtr = weakPtr.lock();
if (sharedPtr) {
std::cout << "Thread " << std::this_thread::get_id() << " - Value: " << *sharedPtr << std::endl;
}
}
int main() {
std::shared_ptr<int> sharedPtr(new int(20));
std::weak_ptr<int> weakPtr = sharedPtr;
std::thread thread1(threadFunction, weakPtr);
std::thread thread2(threadFunction, weakPtr);
thread1.join();
thread2.join();
return 0;
}
unique_ptr
- **示例代码**:
```cpp
#include
#include
class MyClass2 {
public:
MyClass2() {
std::cout << "MyClass2 constructor called." << std::endl;
}
~MyClass2() {
std::cout << "MyClass2 destructor called." << std::endl;
}
void printMessage() {
std::cout << "This is a message from MyClass2." << std::endl;
}
};
int main() {
std::unique_ptr uniquePtr(new MyClass2);
uniquePtr->printMessage();
// 不能进行复制操作,以下是错误的
// std::unique_ptr anotherUniquePtr = uniquePtr;
// 可以通过std::move进行所有权转移
std::unique_ptr anotherUniquePtr = std::move(uniquePtr);
anotherUniquePtr->printMessage();
// 当最后一个拥有对象所有权的unique_ptr离开作用域时,对象会被销毁
return 0;
}
```
- **使用场景**:当你想要确保一个对象在某个作用域结束时自动被销毁,并且这个对象的所有权是独占的,就适合使用`unique_ptr`。比如在函数内部动态分配了一个资源(如上述代码中的`MyClass2`对象),当函数返回时,希望自动释放这个资源,避免内存泄漏。
#include
#include
#include
#include
std::mutex mutex_;
std::unique_ptr<int> uniquePtr;
void threadFunction1() {
std::lock_guard<std::mutex> guard(mutex_);
uniquePtr.reset(new int(10));
}
void threadFunction2() {
std::unique_ptr<int> localPtr;
{
std::lock_guard<std::mutex> guard(mutex_);
localPtr = std::move(uniquePtr);
}
if (localPtr) {
std::cout << "Thread " << std::this_thread::get_id() << " - Value: " << *localPtr << std::endl;
}
}
int main() {
std::thread thread1(threadFunction1);
std::thread thread2(threadFunction2);
thread1.join();
thread2.join();
return 0;
}
void*
指针
#include
#include
int main() {
int num = 10;
void* voidPtr = #
int* intPtr = static_cast<int*>(voidPtr);
std::cout << "The value of num is: " << *intPtr << std::endl;
double doubleNum = 3.14;
voidPtr = &doubleNum;
double* doublePtr = static_cast<double*>(voidPtr);
std::cout << "The value of doubleNum is: " << *doublePtr << std::endl;
return 0;
}
void*
可以用来存储和传递不同类型的数据。例如,在一个简单的缓存系统中,缓存的数据类型可能各种各样(整数、浮点数、结构体等),可以用void*
来存储这些数据,然后通过额外的标记或者类型信息来在合适的时候进行正确的类型转换和解引用。void*
指针被广泛用于一些通用的函数接口,如内存分配函数malloc
返回的就是void*
指针。在C++ 中调用这些C语言函数时,也需要正确地处理void*
指针。例如:#include
#include
int main() {
// 使用C语言的malloc函数分配内存,返回void*指针
void* memory = malloc(sizeof(int));
int* intMemory = static_cast<int*>(memory);
*intMemory = 5;
std::cout << "The value stored in allocated memory is: " << *intMemory << std::endl;
// 释放内存,C++中可以使用free函数(因为它来自C标准库)
free(memory);
return 0;
}