本文详细介绍了C++11语法中的新特性,包括移动语义与右值引用、新的字符串和数字字面量、智能指针以及Lambda表达式等。文章还深入讲解了C++11中的auto关键字、range-based for循环和nullptr等语法基础,并展示了函数与对象、容器与算法、线程支持等多个方面的示例代码。
C++11新特性介绍移动语义与右值引用
C++11引入了移动语义和右值引用,以提高资源管理的效率。通过移动语义,可以将资源从一个对象转移到另一个对象,而不需要进行深拷贝。右值引用(r-value reference)是实现这一功能的关键。右值引用通过&&
符号表示。
示例代码
#include <iostream>
#include <string>
class String {
public:
String(const std::string& str) : data(new std::string(str)) {}
String(String&& other) noexcept : data(other.data) {
other.data = nullptr;
}
~String() { delete data; }
String& operator=(String&& other) noexcept {
if (this != &other) {
delete data;
data = other.data;
other.data = nullptr;
}
return *this;
}
private:
std::string* data;
};
int main() {
String s1("Hello, World!");
String s2 = std::move(s1); // 使用移动语义
std::cout << *s2.data << std::endl;
return 0;
}
新的字符串和数字字面量
C++11引入了新的字符串和数字字面量,使代码更简洁。这包括原始字符串字面量、十六进制浮点数等。
示例代码
#include <iostream>
int main() {
// 原始字符串字面量
const char* str = R"(This is a "raw string" with \n in it.)";
std::cout << str << std::endl;
// 十六进制浮点数
double d1 = 0x1.23p10;
std::cout << d1 << std::endl;
// 十六进制整数
int hex = 0x12345678;
std::cout << hex << std::endl;
return 0;
}
智能指针
C++11引入了智能指针,如std::unique_ptr
和std::shared_ptr
,以简化内存管理。std::unique_ptr
提供了独占所有权的智能指针,而std::shared_ptr
则允许多个指针共享一个对象的生命周期。
示例代码
#include <iostream>
#include <memory>
int main() {
// 使用 std::unique_ptr
std::unique_ptr<int> ptr1(new int(10));
std::cout << *ptr1 << std::endl;
// 使用 std::shared_ptr
std::shared_ptr<int> ptr2 = std::make_shared<int>(20);
std::cout << *ptr2 << std::endl;
// 复制 shared_ptr
std::shared_ptr<int> ptr3 = ptr2;
std::cout << *ptr3 << std::endl;
return 0;
}
Lambda表达式
Lambda表达式允许在代码中定义匿名函数。这对于编写简洁、可读性高的代码非常有用。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 Lambda 表达式
auto is_even = [](int x) { return x % 2 == 0; };
std::vector<int> even_numbers;
std::copy_if(v.begin(), v.end(), std::back_inserter(even_numbers), is_even);
for (int num : even_numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
C++11语法基础
auto关键字
auto
关键字允许编译器自动推断变量类型,从而简化代码。这在处理复杂类型时尤其有用。
示例代码
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 auto 关键字
auto sum = 0;
for (auto it = v.begin(); it != v.end(); ++it) {
sum += *it;
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
range-based for循环
range-based for循环允许更简洁地遍历容器中的元素。这种循环不需要显式使用迭代器。
示例代码
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 range-based for 循环
for (int value : v) {
std::cout << value << " ";
}
std::cout << std::endl;
return 0;
}
decltype关键字
decltype
关键字用于获取变量或表达式的类型。这在模板元编程中特别有用。
示例代码
#include <iostream>
int main() {
int x = 5;
// 使用 decltype
decltype(x) y = 10;
std::cout << "x 的类型是: " << typeid(decltype(x)).name() << std::endl;
std::cout << "y 的类型是: " << typeid(decltype(y)).name() << std::endl;
return 0;
}
nullptr
nullptr
是一个专门用于空指针的常量,取代了传统的NULL
定义,以提高代码的安全性和可读性。
示例代码
#include <iostream>
int main() {
int* ptr = nullptr;
if (ptr == nullptr) {
std::cout << "ptr 是空指针" << std::endl;
}
return 0;
}
C++11中的函数与对象
异常处理改进
C++11增强了异常处理的能力,包括新的noexcept
关键字和std::terminate
函数。noexcept
用于声明函数不会抛出异常,而std::terminate
用于处理未捕获的异常。
示例代码
#include <iostream>
#include <exception>
void func() noexcept {
throw std::runtime_error("Exception occurred");
}
int main() {
try {
func();
} catch (const std::exception& e) {
std::cout << "Caught an exception: " << e.what() << std::endl;
}
return 0;
}
类型推断与模板推导
C++11引入了类型推断,使得模板推导更加灵活。这在使用模板函数和类时特别有用。
示例代码
#include <iostream>
#include <type_traits>
template<typename T>
void printType(const T& value) {
std::cout << "类型是: " << typeid(T).name() << std::endl;
}
int main() {
int x = 10;
std::string str = "Hello, World!";
printType(x);
printType(str);
return 0;
}
类成员初始化
C++11允许在类的构造函数中直接初始化成员变量,简化了代码的编写。
示例代码
#include <iostream>
class MyClass {
public:
MyClass(int x, std::string y) : value(x), message(y) {}
void print() {
std::cout << "Value: " << value << ", Message: " << message << std::endl;
}
private:
int value;
std::string message;
};
int main() {
MyClass obj(10, "Hello, World!");
obj.print();
return 0;
}
C++11中的容器与算法
新增的容器类型
C++11引入了几个新的标准库容器,如std::unordered_set
和std::unordered_map
,这些容器提供了哈希表的实现,提高了插入和查找的效率。
示例代码
#include <iostream>
#include <unordered_set>
int main() {
std::unordered_set<int> set = {1, 2, 3, 4, 5};
// 插入元素
set.insert(6);
// 查找元素
if (set.find(3) != set.end()) {
std::cout << "找到了 3" << std::endl;
}
return 0;
}
标准库的算法更新
C++11更新了标准库中的算法,增加了新的算法和改进了现有算法的效率。例如,std::copy_if
等算法提供了更强大的功能。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 std::copy_if
std::vector<int> even_numbers;
std::copy_if(v.begin(), v.end(), std::back_inserter(even_numbers), [](int x) { return x % 2 == 0; });
for (int num : even_numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
容器与算法的结合使用
C++11中的容器和算法结合使用可以编写高效、简洁的代码。这在处理复杂数据结构时尤其有用。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 std::for_each
std::for_each(v.begin(), v.end(), [](int& x) { x *= 2; });
for (int num : v) {
std::cout << num << " ";
}
std::cout << std::endl;
// 更复杂的容器与算法结合使用
std::vector<int> v2 = {10, 20, 30, 40, 50};
// 分组并计数
std::map<int, int> count;
std::for_each(v2.begin(), v2.end(), [&count](int x) {
count[x]++;
});
for (const auto& pair : count) {
std::cout << "Value: " << pair.first << ", Count: " << pair.second << std::endl;
}
return 0;
}
C++11中的线程支持
基本线程操作
C++11引入了std::thread
,使得线程编程更加简单和安全。
示例代码
#include <iostream>
#include <thread>
void task(int id) {
std::cout << "Task " << id << " is running on thread " << std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t1(task, 1);
std::thread t2(task, 2);
t1.join();
t2.join();
return 0;
}
互斥锁和条件变量
C++11提供了std::mutex
和std::condition_variable
,用于线程间的同步。
示例代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; });
std::cout << "Worker thread: " << std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t1(worker);
std::thread t2(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_all();
t1.join();
t2.join();
return 0;
}
原子操作
C++11提供了std::atomic
,允许对变量进行原子操作,以避免多线程环境中的数据竞争。
示例代码
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<int> counter(0);
void increment() {
for (int i = 0; i < 10000; ++i) {
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl;
return 0;
}
线程间的数据共享
线程间的数据共享是一个常见的应用场景,可以使用互斥锁来确保线程安全。
示例代码
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int shared_data = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
std::lock_guard<std::mutex> lock(mtx);
++shared_data;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final shared_data value: " << shared_data << std::endl;
return 0;
}
线程池的实现
线程池是一种常见的线程管理机制,可以提高程序的响应速度和资源利用率。
示例代码
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
std::vector<std::thread> workers;
bool done = false;
void worker() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return done || !workers.size(); });
if (done) {
break;
}
// 执行任务
std::cout << "Worker thread: " << std::this_thread::get_id() << " is working" << std::endl;
}
}
int main() {
for (int i = 0; i < 4; ++i) {
workers.emplace_back(worker);
}
std::this_thread::sleep_for(std::chrono::seconds(3));
{
std::lock_guard<std::mutex> lock(mtx);
done = true;
}
cv.notify_all();
for (auto& worker : workers) {
worker.join();
}
return 0;
}
C++11代码示例与练习
实际应用案例
C++11中的新特性可以用于各种实际应用,例如高并发程序、复杂的数据结构处理等。
示例代码
#include <iostream>
#include <vector>
#include <thread>
#include <algorithm>
void processChunk(std::vector<int>& chunk) {
std::vector<int> sortedChunk(chunk.size());
std::sort(chunk.begin(), chunk.end());
}
int main() {
std::vector<int> data = {1, 3, 5, 2, 4, 6, 8, 7, 9};
std::vector<std::vector<int>> chunks;
int chunkSize = data.size() / 3;
for (int i = 0; i < data.size(); i += chunkSize) {
std::vector<int> chunk;
chunk.reserve(chunkSize);
std::copy_n(data.begin() + i, chunkSize, std::back_inserter(chunk));
chunks.push_back(chunk);
}
std::vector<std::thread> threads;
for (auto& chunk : chunks) {
threads.emplace_back(processChunk, std::ref(chunk));
}
for (auto& thread : threads) {
thread.join();
}
for (const auto& chunk : chunks) {
for (int num : chunk) {
std::cout << num << " ";
}
std::cout << std::endl;
}
return 0;
}
常见问题解答
Q: 如何正确使用std::unique_ptr
?
A: std::unique_ptr
是一种独占所有权的智能指针。通常用于避免手动管理内存,例如:
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> ptr(new int(10));
std::cout << *ptr << std::endl;
// 不能复制 unique_ptr
// std::unique_ptr<int> ptr2 = ptr;
// 可以移动 unique_ptr
std::unique_ptr<int> ptr2 = std::move(ptr);
std::cout << *ptr2 << std::endl;
return 0;
}
Q: 如何使用std::shared_ptr
?
A: std::shared_ptr
允许多个指针共享一个对象的生命周期。当没有指针指向该对象时,对象会被自动删除。
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> ptr1 = std::make_shared<int>(10);
std::shared_ptr<int> ptr2 = ptr1;
std::cout << *ptr1 << std::endl;
std::cout << *ptr2 << std::endl;
return 0;
}
练习题与参考解答
练习1: 实现一个简单的线程安全计数器。
参考解答:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int counter = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
std::lock_guard<std::mutex> lock(mtx);
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl;
return 0;
}
练习2: 使用std::unordered_map
存储和查找数据。
参考解答:
#include <iostream>
#include <unordered_map>
int main() {
std::unordered_map<std::string, int> map = {{"apple", 1}, {"banana", 2}, {"cherry", 3}};
// 插入元素
map["date"] = 4;
// 查找元素
if (map.find("banana") != map.end()) {
std::cout << "找到了 banana" << std::endl;
}
// 删除元素
map.erase("apple");
return 0;
}
练习3: 实现一个简单的Lambda表达式,用于过滤和打印元素。
参考解答:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
auto is_even = [](int x) { return x % 2 == 0; };
std::vector<int> even_numbers;
std::copy_if(v.begin(), v.end(), std::back_inserter(even_numbers), is_even);
for (int num : even_numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
通过这些示例和练习,你可以更好地理解和掌握C++11的新特性和语法。
共同学习,写下你的评论
评论加载中...
作者其他优质文章