C++模板基础(三)传值还是传引用?
最开始,C++就提供了传值调用和传引用调用两种传参方式,但是决定选择哪种并不是那么容易:通常复杂对象传引用的成本更低但也更复杂。C++11新增了移动语义,这意味着我们可能通过不同的方式来传引用。:1.X const&:常左值引用。 2.X&非常量左值引用。 3.X&&右值引用。通过移动语义传递引用对象。 我们建议在函数模板中使用传值的方式传参,除非有以下情况: **1.**无法拷贝(对于左值来说,自C++17起,可以按值传递临时实体)。 **2.**参数用于返回数据。 **3.**模板需要保留原始实参的所有属性,只是通过转发调用其他函数。 **4.**性能可获得明显提升。 传值按值传递实参时,原则上会拷贝每个参数,对于类来说,会调用类的拷贝构造函数,因此每个参数都成为传递实参的副本。 调用拷贝构造函数的成本可能会很高,不过我们有很多种策略可以避免高昂的拷贝成本。此外,编译器也可以根据情况优化掉拷贝操作,变为移动语义等,可以让复杂对象的传递成本变得很低。 例如。让我们看一个函数模板: 12345template <typename...
C++模板基础(二)移动语义和enable_if<>
移动语义时C++11引入的重要特性之一。移动语义可以用来优化拷贝和赋值操作,可以将内部资源从源对象移动到目标对象,而不复制它们。使用移动语义的前提是移动后源对象不再需要其内部值或者状态。 移动语义对模板设计有重要影响,在泛型代码中引入了特殊规则来支持移动语义。本帖将介绍这些规则。 完美转发简介假设想要编写转发传递实参的基本属性的泛型代码,存在以下三种情况: 1.可修改对象应使用转发,以便它们仍可修改。 2.常量对象应该作为只读对象转发。 3.可移动对象应该作为可移动对象转发。 具体来说,假如对一个类A,一个转发它的函数应该有三种情况: 12345678910111213141516class A{};void foo(A &&a){ std::cout << "foo() for movable object\n";}void foo(const A &a){ std::cout << "foo() for constant...
C++模板基础(一)模板基本技巧(下)
成员模板对于嵌套类和成员函数来说,它们也有可能是模板,下面让我们用C++模板入门(二)类模板中的Stack<>类继续演示。 为了方便,我们截取一部分: 12345678910111213141516171819202122232425262728293031template <typename T>class Stack {public: Stack() = default; ~Stack() = default; void push(const T& value) { stack.push_back(value); } void pop() { assert(!stack.empty()); stack.pop_back(); } const T& top() const { assert(!stack.empty()); return stack.back(); ...
C++模板基础(一)模板基本技巧(上)
关键字typenameC++在标准化过程中,引入了关键字typename来说明模板内部的某个标识符是一种类型: 12345678910111213141516171819202122232425#include <iostream>class B{public: using Subtype = int;};template <typename T>class A{public: typename T::Subtype *ptr;};int main(){ A<B> a; a.ptr = new int(1); std::cout << *a.ptr << std::endl; delete a.ptr; return...
C++模板入门(四)变参模板(下)
变参类模板和变参表达式变参表达式计算应用变参表达式不仅仅可以传递所有参数,而且可以进行计算: 123456789101112131415161718192021222324252627282930313233#include <iostream>template <typename T>class AddSpace{private: const T &elem;public: AddSpace(const T &elem) : elem(elem) {} friend std::ostream &operator<<(std::ostream &os, const AddSpace<T> &obj) { return os << obj.elem << ' '; }};template <typename... Args>void...
C++模板入门(四)变参模板(上)
变参模板简介从C++11标准起,模板参数可以接收任意数量可变的模板实参。这个特性允许在必须传递任意数量和类型的实参的地方使用模板。一个典型的应用是通过类或者框架传递数量和类型都未定的参数,另一个应用是提供泛型代码处理任意数量和类型的参数。 变参模板实例一个接收任意多参数的print()函数如下: 12345678910111213141516#include <bitset>#include <iostream>void print() {}template <typename T, typename... Types>void print(const T &firstArg, const Types &...args){ std::cout << firstArg << std::endl; print(args...);}int main(){ print(7.5, "hello",...
C++模板入门(三)非类型参数
非类型的类模板参数先让我们用标准库中的std::array定义一个Stack: 1234567891011121314151617181920212223242526272829303132333435363738template <typename T, std::size_t Maxsize>class Stack{private: std::array<T, Maxsize> stack; std::size_t numElems = 0;public: Stack() = default; ~Stack() = default; void push(const T &value) { stack[numElems++] = value; } void pop() { assert(numElems > 0); --numElems; } const T &top()...
C++多线程入门(三)lock_guard和unique_lock
一、std::lock_guard类1.lock_guard是一个模板类, 用于管理互斥量的加锁和解锁在需要加锁的代码块中创建一个lock_guard对象(调用构造函数), 在lock_guard对象的生命周期结束时(调用析构函数), 会自动解锁 lock_guard禁用拷贝构造函数和赋值运算符,无法复制和移动 常用构造函数: 1explicit lock_guard( mutex_type& m ); 以一个互斥量作为参数。 使用方法: 12345678910111213141516171819202122232425262728#include <iostream>#include <thread>#include <mutex>using std::cin;using std::cout;std::mutex mtx;int shared_data = 0;void func(){ for (int i = 0; i < 1000000; i++) { ...
C++模板入门(二)类模板
一、类模板初探类模板的实现下面是一个简单的Stack模板类 123456789101112131415161718192021222324252627282930template <typename T>class Stack {public: Stack() = default; ~Stack() = default; void push(const T& value) { stack.push_back(value); } void pop() { assert(!stack.empty()); stack.pop_back(); } const T& top() const { assert(!stack.empty()); return stack.back(); } bool empty() const { return...

