c++11笔记

追踪返回类型:

就是返回类型后置,

可用于函数模块,也被广泛用于转发函数(如:可以实现参数和返回类型不同时的转发)中,还可用在函数指针、函数引用中;

 

类型安全:

宏的弱点:在于其定义的只是在预处理阶段的名字

枚举类型的缺点:全局可见,对个枚举类型内的枚举值可能会发生冲突,导致编译失败;

C++98枚举缺点:

非强类型作用域,允许隐式转换为整型,占用存储空间及符号性不确定

C++11:枚举类,又称强类型枚举,在enum后面加上class,即可,还可以指定出wchar_t以外的任何整型;

enum class Type: char { General, Light, Medium, Heavy };

优点:强作用域,转换限制,可以指定底层类型;

 

智能指针

shared_ptr参与指向内存的引用计数

weak_ptr不参与,可以通过成员lock指向对象内存,但不拥有该内存。

unique_prt代替了以前使用auto_ptr的。而shared_ptr以及weak_ptr则可用在用户需要引用计数的地方。

智能指针能帮助用户进行有效的堆内存管理,但需要显示声明,而完全不用考虑回收指针类型的内存管理方案更讨人喜欢。

 

垃圾回收分类

垃圾是指:把之前使用过,现在不再使用或没有任何指针再指向的内存空间;

垃圾回收机制是指:将这些“垃圾”收集起来以便再次利用的机制;

1.基于引用计数的垃圾回收器:

优点副作用较小(不会有对系统缓存或交换空间造成的冲击),缺点容易形成“环形引用”问题,由于计数带来的额外开销并不小,所以在实用上有一定的限制

2.基于跟踪处理的垃圾回收器:

与1相比,被更广泛的应用。基本方法是产生跟踪对象的关系图,然后进行垃圾回收。

三种算法:标记-清除;标记-整理;标记-拷贝;

 

C++与垃圾回收:

由于通过引用计数不能解决如“环形引用”的问题,如因多线程程序等而引入的内存管理上的困难,程序员可能需要垃圾回收,如第三方C++垃圾回收库-Boehm,但可移植性较差。

C++11中的“最小垃圾回收支持”,通过语言的约束来保证安全的垃圾回收机制。

要保证安全的垃圾回收,首先必须知道C/C++语言中什么样的行为可能导致垃圾回收中出现的“不安全”状况。简单来说,不安去源自于C/C++语言对指针的“放纵”,即允许过分灵活的使用。当发生指针进行自加或自减操作,或指针被异或覆盖再恢复时,会触发垃圾回收。

定义了“安全”(或称安全派发)指针的操作(即安全派发操作):

1.在解引用基础上的引用,如&*p

2.定义明确的指针操作:如:p+1

3.定义明确的指针转换:如:static_cast<void*>(p)

4.指针和整型之间的reinterpret_cast,如reinterpret_cast<intptr_t>(p)

intptr_t是C++11中一个可选择实现的类型,其长度等于平台上指针的长度(通过decltype声明)

异或不是安全派发操作

 pointer_safety get_pointer_safety() noexcept # 查询确认编译器是否支持最小垃圾回收

声明该指针所指的内存为“可到达”的:

void declare_reachable(void* p);

template<class T> T *undeclare_reachable(T *p) noexcept;

declare_reachable和undeclare_reachable只是确立了一个代码范围,即两者之间的代码运行中,指针对象不会被垃圾回收器回收。

在一大片连续的堆内存上进行指针式操作,为了让垃圾回收器不关心该区域,可以用如下代码:

void declare_no_pointers(char* p, size_t n) noexcept;

void undelcare_no_pointers(char *p, size_t n) noexcept;

指定的是从p开始的连续n的内存。

不向后兼容,对于老的代码我们需要限制指针的使用或使用上述两种方式,让一些不安全的指针使用免于垃圾回收器的检查。

仅限于在new操作符分配的内存,而malloc分配的内存则被认为总是可达的。因此,有malloc等较老代码的堆内存还是必须由程序员自己控制。

显示的delete使用与垃圾回收并不会形成冲突,可以保证代码最大可能性的向前兼容(面向未来)。

理想情况下,程序员应该总是在栈上分配变量,这样变量能够有效地自动释放。

 

    std::tuple<int, char, std::string> a(std::make_tuple(1,'H', "Hello"));
    int n = std::get<0>(a);
    char c = std::get<1>(a);
    std::string d = std::get<2>(a);

 

变长模板函数远强于变长函数,因为变长模板函数不会丢失参数的类型信息,示例代码如下:

void Printf(const char *s) {
    while(*s) {
        if (*s == '%' && *++s != '%') 
            throw std::runtime_error("invalid format string: missing arguments");
        std::cout << *s++;
    }
}

template<typename T, typename... Args>
void Printf(const char* s, T value, Args... args) {
    while(*s) {
        if (*s == '%' && *++s != '%')  {
            std::cout << value;
            return Printf(++s, args...);
        }
        std::cout << *s++;
    }
    throw std::runtime_error("extra arguments provided to Printf");
}

 Printf("hello %s\n", std::string("world").c_str());

 

posted @ 2021-04-22 10:27  绍荣  阅读(90)  评论(0编辑  收藏  举报