C++11 是 C++的一个版本,由C++03改进而来,原来计划是在2010年前发布,所以经常可以看到C++0x。C++11添加了很多非常好用的特性,甚至被人们认为是一门新的语言。C++11在GCC 4.8中支持基本完善。以下内容为转载,添加了一些笔记。
如果编译器在定义一个变量的时候可以推断出变量的类型,不用写变量的类型,你只需写auto即可
auto str = "sissie";
assert(typeid(str) == typeid(const char *));
auto处理引用时默认是值类型,可以指定&作为修饰符强制它作为引用,auto自动获取指针类型,也可以显示地指定指针类型
int& foo();
auto i = foo(); // int
auto& ri = foo(); // int&
int* bar();
auto pi = bar(); // int*
auto* pi = bar(); // int*
在迭代器中使用auto,简化代码
std::vector<std::string> vs{{"sissie", "robin", "playjokes", "sky", "hatlonely"}};
for (auto it = vs.begin(); it != vs.end(); ++it) {
std::cout << *it << ", ";
}
在模板中使用auto
template <typename BuiltType, typename Builder>
void makeAndProcessObject(const Builder& builder)
{
BuiltType val = builder.makeObject();
// do stuff with val
}
MyObjBuilder builder;
makeAndProcessObject<MyObj>(builder);
// 使用auto只需要一个模板参数,让编译器自动推导
template <typename Builder>
void makeAndProcessObject(const Builder& builder)
{
auto val = builder.makeObject();
// do stuff with val
}
MyObjBuilder builder;
makeAndProcessObject(builder);
decltype 返回操作数的类型,可以对基本上任何类型使用decltype,包括函数的返回值
int ia[10];
decltype(ia) ib; // int ib[10];
新的函数返回值声明语法,把返回类型放在函数声明的后面,用auto代替前面的返回类型
// 这两种函数声明方式等效
int multiply(int x, int y);
auto multiply(int x, int y) -> int;
// 返回auto
template <typename Builder>
auto makeAndProcessObject(const Builder& builder) -> decltype(builder.makeObject())
{
auto val = builder.makeObject();
// do stuff with val
return val;
}
区间迭代,for循环遍历容器
std::vector<std::string> vs{{"sissie", "robin", "playjokes", "sky", "hatlonely"}};
for (const auto& name: vs) {
std::cout << name << ", ";
}
nullptr 是C++11中新加的关键字,用来表示空指针,替代原来的NULL,nullptr不能转换成int
C++11中得lambda表达式用来定义和创建匿名函数,lambda表达式语法形式如下:
[ capture ] ( params ) mutable exception attribute -> ret { body } // (1)
[ capture ] ( params ) -> ret { body } // (2)
[ capture ] ( params ) { body } // (3)
[ capture ] { body } // (4)
(1) 是完整的 lambda 表达式形式
(2) const 类型的 lambda 表达式,该类型的表达式不能改捕获(“capture”)列表中的值
(3) 省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
(4) 省略了参数列表,类似于无参函数 f()
capture:capture 为捕获的lambda所在作用域范围内可见的局部变量列表
params:参数列表
mutable exception attribute:lambda是否可以更改捕获变量以及是否有异常抛出
ret:返回类型
// 数组累加
std::vector<int> vi{{1, 2, 3, 4, 5, 6, 7, 8, 9}};
int total = 0;
std::for_each(vi.begin(), vi.end(), [&total](int i) {
total += i;
});
// 数组绝对值
// 单一的return语句,编译其可以推导出返回类型,多个return语句需要显示指定返回类型
std::transform(vi.begin(), vi.end(), [](int i) -> int {
if (i < 0) {
return -i;
} else {
return i;
}
});
// mutable
size_t i = 42;
auto f = [i]() mutable {
return ++i;
};
i = 0;
std::cout << f() << std::endl; // 43
std::cout << f() << std::endl; // 44
C++11新添加初始化列表std::initializer_list<>类型,可以通过{}语法来构造初始化列表
// 容器初始化
// {1, 2, 3, 4, 5}实际上是一个std::initializer_list<int>类型
std::vector<int> vi = {1, 2, 3, 4, 5};
std::vector<std::string> vs{{"sissie", "robin", "playjokes", "sky", "hatlonely"}};
std::map<int, std::string> mis = {
{1, "c"},
{2, "java"},
{3, "c++"}
};
// 初始化列表参数
void print_initializer_list(std::initializer_list<int> il) {
for (auto i: il) {
std::cout << i << ", ";
}
std::cout << endl;
}
print_initializer_list({1, 2, 3, 4, 5, 6});
// 返回初始化列表
std::vector<std::string> my_array() {
return {"sissie", "robin", "playjokes", "sky", "hatlonely"};
}
加入两个新的标识符:
class B
{
public:
virtual void f(int) {std::cout << "B::f" << std::endl;}
};
class D : public B
{
public:
virtual void f(int) override final {std::cout << "D::f" << std::endl;}
};
默认或禁用函数,当我们定义了自己的带参数的构造函数时,编译器将不再生成默认的构造函数,如果此时想使用默认的构造函数,则必须显式地声明并定义不带参数的构造函数。在C++11中,我们可以使用default关键字来表明我们希望使用默认的构造函数。类似的,当我们不想外部使用编译器自动生成的构造函数或赋值函数时,我们一般需要将其声明成protected或private的。在C++ 11中,我们可以使用delete关键字来表明我们不希望编译器生成默认的构造函数或赋值函数。
class Person {
public:
Person() = default;
Person(const Person& person) = delete;
};
C++11允许成员变量就地初始化
class Person { private: std::string _name = "sissie"; }
委托构造函数,一个委托构造函数使用它所属类的其他构造函数执行它的初始化过程
class SaleData {
SaleData(std::string booknum, uint32_t units_sold, double price) :
_booknum(booknum), _units_sold(unit_sold), _price(price) {}
SaleData() : SaleData("", 0, 0) {}
SaleData(std::string booknum) : SaleData(booknum, 0, 0) {}
};
左值和右值是针对表达式而言,表达式之后依然存在的对象是左值,表达式之后不再存在的临时对象为右值
左值可以对其取地址,右值不能
int i = 0;
std::string hello = "hello";
std::string world = "world";
const int& ri = 1;
// 左值:i, ++i, hello, world
// 右值:i++, hello + world, ri
拷贝临时对象性能问题,考虑如下字符串初始化
std::string str1 = "a";
// str1 + "b" 生成一个临时对象,再用这个临时对象去构造str2
// 而这个临时对象在构造完str2后就被释放,这个对象并没有用到,却需要调用一次构造函数
std::string str2 = str1 + "b";
如果我们能确定某个值是一个非常量右值(或者是一个以后不会再使用的左值),则我们在进行临时对象的拷贝时,可以不用拷贝实际的数据,而只是窃取实际数据的指针,C++11中引入的右值引用正好可用于标识一个非常量右值。C++ 11中用&表示左值引用,用&&表示右值引用
移动构造函数
// MemoryBlock.h
#pragma once
#include <iostream>
#include <algorithm>
class MemoryBlock {
public:
// Simple constructor that initializes the resource.
explicit MemoryBlock(size_t length) : _length(length), _data(new int[length]) {
std::cout << "In MemoryBlock(size_t). length = " << _length << "." << std::endl;
}
// Destructor.
~MemoryBlock() {
std::cout << "In ~MemoryBlock(). length = " << _length << ".";
if (_data != NULL) {
std::cout << " Deleting resource.";
// Delete the resource.
delete[] _data;
}
std::cout << std::endl;
}
// Copy constructor.
MemoryBlock(const MemoryBlock& other) : _length(other._length), _data(new int[other._length]) {
std::cout << "In MemoryBlock(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
std::copy(other._data, other._data + _length, _data);
}
// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other) {
std::cout << "In operator=(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
_length = other._length;
_data = new int[_length];
std::copy(other._data, other._data + _length, _data);
}
return *this;
}
// Move constructor.
MemoryBlock(MemoryBlock&& other) : _length(0), _data(NULL) {
std::cout << "In MemoryBlock(MemoryBlock&&). length = "
<< other._length << ". Moving resource." << std::endl;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = NULL;
other._length = 0;
}
// Move assignment operator.
MemoryBlock& operator=(MemoryBlock&& other) {
std::cout << "In operator=(MemoryBlock&&). length = "
<< other._length << "." << std::endl;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = NULL;
other._length = 0;
}
return *this;
}
// Retrieves the length of the data resource.
size_t Length() const {
return _length;
}
private:
size_t _length; // The length of the resource.
int* _data; // The resource.
};
// rvalue-references-move-semantics.cpp
// compile with: /EHsc
#include "MemoryBlock.h"
#include <vector>
int main() {
// Create a vector object and add a few elements to it.
std::vector<MemoryBlock> v;
v.push_back(MemoryBlock(25));
std::cout << "======================" << std::endl;
v.push_back(MemoryBlock(75));
std::cout << "======================" << std::endl;
// Insert a new element into the second position of the vector.
v.insert(v.begin() + 1, MemoryBlock(50));
std::cout << "======================" << std::endl;
}
// 可以看到下面的输出在push_back的时候,由于参数是一个非常量右值,自动调用了move构造函数
// 下面还有拷贝构造函数是在vector长度增长时拷贝数组产生的,这次拷贝构造也可以优化成move
// 具体实现与编译器有关
// In MemoryBlock(size_t). length = 25.
// In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.
// In ~MemoryBlock(). length = 0.
// ======================
// In MemoryBlock(size_t). length = 75.
// In MemoryBlock(MemoryBlock&&). length = 75. Moving resource.
// In MemoryBlock(const MemoryBlock&). length = 25. Copying resource.
// In ~MemoryBlock(). length = 25. Deleting resource.
// In ~MemoryBlock(). length = 0.
// ======================
// In MemoryBlock(size_t). length = 50.
// In MemoryBlock(MemoryBlock&&). length = 50. Moving resource.
// In MemoryBlock(const MemoryBlock&). length = 25. Copying resource.
// In MemoryBlock(const MemoryBlock&). length = 75. Copying resource.
// In ~MemoryBlock(). length = 75. Deleting resource.
// In ~MemoryBlock(). length = 25. Deleting resource.
// In ~MemoryBlock(). length = 0.
// ======================
// In ~MemoryBlock(). length = 75. Deleting resource.
// In ~MemoryBlock(). length = 50. Deleting resource.
// In ~MemoryBlock(). length = 25. Deleting resource.
std::move显示调用move构造函数,如果类没有move构造函数,会调用copy构造函数。对一个左值使用std::move之后,不应该再使用该对象,对该对象的任何操作都是未定义的。
std::vector<MemoryBlock> v;
MemoryBlock mb(66);
v.push_back(std::move(mb));
阅读笔记
move的使用,首先要实现类的move构造函数或者重载赋值操作符,然后传入一个右值,或者使用move将一个左值转换成右值。
std::forward的:由于声明为f(T&& t)的模板函数的形参t会失去右值引用性质,所以在将t传给更深层函数前,可能会需要回复t的正确引用。在实现模板类时可能会用到。
// vector的无参构造函数初始化vector时,size和capacity都是0
// 之后当capacity不足时,capacity会成倍增加,可以用reverse指定capacity的值
std::vector<int> vi;
assert(vi.size() == 0);
assert(vi.capacity() == 0);
vi.reserve(1024);
assert(vi.size() == 0);
assert(vi.capacity() == 1024);
// vector的构造函数可以传入一个参数指定当前vector的size
// 此构造函数会调用元素的无参构造函数,初始化元素
// 所以元素的类型必须实现无参构造函数,才能调用此构造函数
std::vector<std::string> vs(5);
assert(vs.size() == 5);
assert(vs.capacity() == 5);
vs.push_back("sissie");
assert(vs[5] == "sissie");
assert(vs.size() == 6);
assert(vs.capacity() == 10);
vs.shrink_to_fit();
assert(vs.capacity() == 6);
array是C++11新引入的数组类型,和std::vector不同的是array的长度是固定的,不能动态拓展
template <class T, std::size_t N> struct array
std::array<int, 3> a1{{1, 2, 3}};
std::sort(a1.begin(), a1.end());
C++11引入的新类型,forward_list是单链表(std::list是双链表),只需要顺序遍历的场合,forward_list能更加节省内存,插入和删除的性能高于list
std::forward_list<int> fli{{1, 2, 3, 4}};
std::set std::multiset std::map std::multimap
用平衡树实现的有序的容器,插入、删除和查找的时间复杂度都是O(nlogn)
std::unordered_set std::unordered_multiset std::unordered_map std::unordered_multimap
C++11引入的新类型,用hash实现的无序的容器,插入、删除和查找的时间复杂度都是O(1),在不关注容器内元素顺序的场合,使用unordered的容器能获得更高的性能
std::unordered_set<int> usi = {{11, 22, 33, 44, 55, 66, 77, 88, 99, 0}};
assert(usi.size() == 10);
usi.insert(66);
assert(usi.size() == 10);
// unordered_set是无序的
// 0,99,88,77,66,55,44,33,22,11,
for (const auto& i: usi) {
std::cout << i << ",";
}
std::cout << std::endl;
// set是有序的
// 0,11,22,33,44,55,66,77,88,99,
std::set<int> si = {{11, 22, 33, 44, 55, 66, 77, 88, 99, 0}};
for (const auto& i: si) {
std::cout << i << ",";
}
std::cout << std::endl;
// multiset中可以插入相同的值
std::unordered_multiset<int> umsi = {{11, 22, 33, 44, 55, 66, 77, 88, 99, 0}};
assert(umsi.size() == 10);
assert(umsi.count(66) == 1);
umsi.insert(66);
assert(umsi.size() == 11);
assert(umsi.count(66) == 2);
std::unordered_map<std::string, double> book_price_map{{
{"C++ Primer", 128.00},
{"UNIX 环境高级编程", 99.00},
{"HBase 权威指南", 89.00},
{"MapReduce 设计模式", 49.00}
}};
for (const auto& book_price_pair: book_price_map) {
std::cout << book_price_pair.first << " => " << book_price_pair.second << std::endl;
}
#include <cassert>
#include <memory>
int main() {
{
std::unique_ptr<int> upi(new int(6));
}
{
// 用make_shared来初始化shared_ptr
std::shared_ptr<int> spi = std::make_shared<int>(6);
// use_count获取引用计数
assert(spi.use_count() == 1);
{
std::shared_ptr<int> spi_shared(spi);
assert(spi.use_count() == 2);
}
assert(spi.use_count() == 1);
}
{
std::shared_ptr<int> spi = std::make_shared<int>(6);
assert(spi.use_count() == 1);
// 通过shared_ptr来构造weak_ptr
std::weak_ptr<int> wpi(spi);
// weak_ptr不改变引用计数
assert(spi.use_count() == 1);
assert(wpi.use_count() == 1);
// lock() 获取weak_ptr引用的shared_ptr
assert(*wpi.lock() == 6);
// expired() 返回引用的对象是否已经释放
assert(!wpi.expired());
}
return 0;
}
shared_ptr提供get函数获取对象的指针
typedef basic_regex<char> regex
typedef basic_regex<wchar_t> wregex
typedef sub_match<const char*> csub_match
typedef sub_match<const wchar_t*> wcsub_match
typedef sub_match<std::string::const_iterator> ssub_match
typedef sub_match<std::wstring::const_iterator> wssub_match
typedef match_results<const char*> cmatch
typedef match_results<const wchar_t*> wcmatch
typedef match_results<std::string::const_iterator> smatch
typedef match_results<std::wstring::const_iterator> wsmatch
match_result成员
正则匹配
#include <iostream>
#include <regex>
#include <cassert>
int main()
{
std::string context = ""
"hatlonely ([email protected]) "
"playjokes ([email protected])";
std::regex mail_regex("(\\w+)@(\\w+)\\.com");
std::smatch mail_result;
// 不能全词匹配 regex_match返回false
assert(!std::regex_match(context, mail_result, mail_regex));
// 可以部分匹配 regex_search返回true
assert(std::regex_search(context, mail_result, mail_regex));
// mail_result被regex_search设置过 返回true
assert(mail_result.ready());
// mail_result中sub_match的个数,两个子表达式加上整个表达式
assert(mail_result.size() == 3);
// mail_result[0]为匹配到的整个字符串
assert(mail_result[0] == "[email protected]");
// mail_result[n]为第n个子表达式匹配到得串(小括号内的串)
assert(mail_result[1] == "hatlonely");
assert(mail_result[2] == "gmail");
// prefix未匹配到的之前的串
assert(mail_result.prefix() == "hatlonely (");
// suffix未匹配到的之后的串
assert(mail_result.suffix() == ") playjokes ([email protected])");
// $` 相当于prefix
// $' 相当于suffix
// $n 第n个子匹配
std::cout << mail_result.format("$` $1 $2") << std::endl;
{
// 相当于循环调用regex_search,迭代器的value_type为match_result
std::sregex_iterator it(context.begin(), context.end(), mail_regex);
std::sregex_iterator end;
for (; it != end; ++it) {
std::cout << (*it)[0] << std::endl;
}
}
{
// 相当于循环调用regex_search,迭代器的value_type为sub_match,相当于match_result[0]
std::sregex_token_iterator it(context.begin(), context.end(), mail_regex);
std::sregex_token_iterator end;
for (; it != end; ++it) {
std::cout << *it << std::endl;
}
}
{
// regex_replace 默认会替换所有匹配到的串,指定format_first_only可以只替换第一个匹配到得串
// hatlonely ([email protected]) playjokes ([email protected])
std::cout << context << std::endl;
// hatlonely (hatlonely) playjokes (playjokes)
std::cout << regex_replace(context, mail_regex, "$1") << std::endl;
// hatlonely (hatlonely) playjokes ([email protected])
std::cout << regex_replace(context, mail_regex, "$1",
std::regex_constants::format_first_only) << std::endl;
}
return 0;
}
构造函数
thread();
// f 是线程执行的函数,可以是函数指针或者是仿函数对象
// args 是函数的参数,(C++11新特新可变模板参数)
template <class Function, class... Args> explicit thread(Function&& f, Args&&... args);
// 线程不可复制
thread(const thread&) = delete;
// 线程可以移动
thread(thread&& other);
thread成员函数
当前线程操作函数,这些函数都定义在std::this_thread命名空间内
#include <iostream>
#include <thread>
// 无参数线程函数
void thread_func_with_no_param() {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::cout << "thread_func_with_no_param" << std::endl;
}
// 带参数线程函数
void thread_func_with_param(int a, int b, int& result) {
std::this_thread::sleep_for(std::chrono::milliseconds(40));
result = a + b;
std::cout << "thread_func_with_param: " << a << " + " << b << " = " << result << std::endl;
}
// 线程仿函数
struct thread_func_struct {
void operator()(int a, int b, int& result) {
std::this_thread::sleep_for(std::chrono::milliseconds(60));
result = a * b;
std::cout << "thread_func_struct: " << a << " * " << b << " = " << result << std::endl;
}
};
void thread_usage() {
int a = 1, b = 2, result1, result2;
std::thread thread1(thread_func_with_no_param);
// 此处的必须使用std::ref传入result1的引用,下面一样
std::thread thread2(thread_func_with_param, a, b, std::ref(result1));
std::thread thread3(thread_func_struct(), a, b, std::ref(result2));
thread1.join();
thread2.join();
thread3.join();
// thread1.detach();
// thread2.detach();
// thread3.detach();
std::cout << "result1: " << result1 << std::endl;
std::cout << "result2: " << result2 << std::endl;
}
多个线程同时访问共享资源的时候需要需要用到互斥量,当一个线程锁住了互斥量后,其他线程必须等待这个互斥量解锁后才能访问它。thread提供了四种不同的互斥量:
std::mutex有如下几个成员函数
构造函数,std::mutex不允许拷贝构造,也不允许move拷贝,最初产生的mutex对象是处于unlocked状态的。
lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面3种情况:
unlock(), 解锁,释放对互斥量的所有权。
try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面3种情况:
std::timed_mutex 比 std::mutex 多了两个成员函数,try_lock_for(),try_lock_until()。
void thread_func1(std::mutex& m) {
for (int i = 0; i < 10; i++) {
m.lock(); // 加锁
std::cout << "thread1 " << i << std::endl;
m.unlock(); // 解锁
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void thread_func2(std::mutex& m) {
for (int i = 0; i < 10; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// lock_guard在构造后加锁,在作用域解释后自动释放锁
std::lock_guard<std::mutex> lg(m);
std::cout << "thread2 " << i << std::endl;
}
}
void mutex_usage() {
std::mutex m;
std::thread thread1(thread_func1, std::ref(m));
std::thread thread2(thread_func2, std::ref(m));
thread1.join();
thread2.join();
}
当std::condition_variable对象的某个wait函数被调用的时候,它使用std::unique_lock(通过std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的std::condition_variable对象上调用了notification函数来唤醒当前线程。
std::condition_variable对象通常使用std::unique_lock来等待,如果需要使用另外的lockable类型,可以使用std::condition_variable_any类
condition_variable成员函数
// wait
void wait(std::unique_lock<std::mutex>& lock);
template <class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
// wait_for
template <class Rep, class Period>
std::cv_status wait_for(
std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time);
template <class Rep, class Period, class Predicate>
bool wait_for(
std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate pred);
// wait_until
template<class Clock, class Duration>
std::cv_status wait_until(
std::unique_lock<std::mutex>& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time);
template<class Clock, class Duration, class Predicate>
bool wait_until(
std::unique_lock<std::mutex>& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Predicate pred);
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id (int id) {
std::unique_lock<std::mutex> lck(mtx);
// 下面两句话是一样的
// while (!ready) cv.wait(lck);
cv.wait(lck, []{return ready;});
std::cout << "thread " << id << '\n';
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}
void condition_variable_usage() {
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i) {
threads[i] = std::thread(print_id, i);
}
std::cout << "10 threads ready to race...\n";
go();
for (auto& th : threads) {
th.join();
}
}
原子类型对象的主要特点就是从不同线程访问不会导致数据竞争(data race)。因此从不同线程访问某个原子对象是良性 (well-defined) 行为,而通常对于非原子类型而言,并发访问某个对象(如果不做任何同步操作)会导致未定义 (undifined) 行为发生。
#include <atomic>
int main() {
std::atomic<int> ai(5);
ai++;
ai += 100;
return 0;
}
标准把随机数抽象成随机数引擎和分布两部分.引擎用来产生随机数,分布产生特定分布的随机数(比如平均分布,正太分布等)
标准提供三种常用的引擎:
第一种是线性同余算法,第二种是梅森旋转算法,第三种带进位的线性同余算法。第一种是最常用的,而且速度也是非常快的.
随机数引擎接受一个整形参数当作种子,不提供的话,会使用默认值,推荐使用random_device来产生一个随机数当作种子
#include <iostream>
#include <random>
int main() {
{
// random_device是一个随机数设备,不同的操作系统有不同的实现,linux下是读取/dev/urandom设备
std::random_device rd;
for (int i = 0; i < 10; i++) {
std::cout << rd() << std::endl;
}
}
{
std::random_device rd;
// 用random_device来为随机数生成器设置种子
std::mt19937_64 mt(rd());
for (int i = 0; i < 10; i++) {
std::cout << mt() << std::endl;
}
// 整数均匀分布
std::uniform_int_distribution<unsigned> dis(1, 100);
for (int i = 0; i < 10; i++) {
std::cout << dis(mt) << std::endl;
}
// 浮点数均匀分布
std::uniform_real_distribution<double> drs(0.0, 1.0);
for (int i = 0; i < 10; i++) {
std::cout << drs(mt) << std::endl;
}
}
}
转载内容来自: https://segmentfault.com/a/1190000003004734