1.内存分配错误

如果无法分配内存,new以及new[]的默认行为都是抛出bad_alloc类型的异常,这个类型在<new>头文件中定义。应该捕获这些异常并且正确地处理异常。
如果不喜欢异常,可以使用旧的C模式,无法分配内存的时候返回一个空指针。C++提供了new以及new[]nothrow版本,如果内存失败将返回nullptr而不是抛出异常,可以使用语法new(nothrow)而不是new做到这一点。

#pragma once#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>
#include <stdio.h>namespace test_exception_errorprocess {auto generalNew() -> void {double *p = nullptr;try {p = new double[10LL*1024*1024*1024];printf("generalNew(), p = %p\n", p);}catch(std::bad_alloc& e) {std::cerr << "generalNew(), Fail to allocate memory." << e.what() << std::endl;}delete [] p;}auto cStyleNew() -> void {double *p = nullptr;p = new(std::nothrow)double[10LL*1024*1024*1024];if(nullptr == p) {std::cerr << "cStyleNew(), Fail to allocate memory." << std::endl;}else {printf("cStyleNew(), p = %p\n", p);}delete[]p;}auto main() -> int {std::cout << "testing exception_errorprocess..." << std::endl;generalNew();cStyleNew();std::cout << "------------------------------" << std::endl;return 0;}
}

以上程序输出:

__cplusplus: 201703
testing exception_errorprocess...
generalNew(), Fail to allocate memory.std::bad_alloc
cStyleNew(), Fail to allocate memory.
------------------------------
The end.

2.构造函数中的错误

如果异常发生在构造函数中,则当前的对象可能只构造了一部分。有的成员已经初始化了,而另外一些成员在异常发生前也许还没有初始化。即使某个对象只构造了一部分,我们也要确保已构造的成员能被正确地销毁。

如果异常离开了构造函数,将永远不会调用对象的析构函数。
因此,应该在异常离开构造函数之前,仔细地清理所有资源,并释放构造函数中分配的所有内存。
资源释放的问题与其它函数遇到的问题类似,但不同之处是离开其它函数时会自动调用析构函数处理内存分配以及释放资源。

如果使用了继承会发生什么呢?父类的构造函数在子类的构造函数之前运行,如果子类构造函数抛出一个异常,如何释放父类构造函数分配的资源呢?实际上,C++保证会运行任何构建完整“子对象”的析构函数。因此,任何没有发生异常的构造函数所对应的析构函数都会运行。

示例:

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception_ctor {class Element {public:Element(){std::cout << "Element ctor called, idx: " << count_++ << std::endl;}~Element(){std::cout << "Element dtor called, idx: " << --count_ << std::endl;}        protected:int val_;static int count_;};int Element::count_ = 0;class Matrix {public:Matrix(int w, int h);~Matrix() {std::cout << "Calling Matrix dtor." << std::endl;for(int i = 0; i < height_; ++i) {delete [] ele_[i];}delete [] ele_;ele_ = nullptr;std::cout << "Matrix dtor called." << std::endl;}private:int width_, height_;Element **ele_;};Matrix::Matrix(int w, int h): width_(w), height_(h), ele_(nullptr) {std::cout << "Calling Matrix ctor." << std::endl;ele_ = new Element*[height_];int i = 0;try {for(i = 0; i < height_; ++i) {std::cout << "i = " << i << std::endl;if(i == 2) throw std::bad_alloc();  // 此句模拟i==2时内存申请失败,抛出异常ele_[i] = new Element[width_];}}catch(...) {std::cerr << "exception occurs, idx: " << i << std::endl;// 释放已经申请的内存for(int j = 0; j < i; ++j) {delete[] ele_[j];}delete[] ele_;ele_ = nullptr;// Translate any exception to std::bad_allocthrow std::bad_alloc();}std::cout << "Matrix ctor called." << std::endl;}auto main() -> int {std::cout << "testing exception ctor..." << std::endl;try{Matrix amatrix(3,4);}catch(...) {std::cerr << "exception(s) occur(s)." << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

以上程序输出:

__cplusplus: 201703
testing exception ctor...
Calling Matrix ctor.
i = 0
Element ctor called, idx: 0
Element ctor called, idx: 1
Element ctor called, idx: 2
i = 1
Element ctor called, idx: 3
Element ctor called, idx: 4
Element ctor called, idx: 5
i = 2
exception occurs, idx: 2
Element dtor called, idx: 5
Element dtor called, idx: 4
Element dtor called, idx: 3
Element dtor called, idx: 2
Element dtor called, idx: 1
Element dtor called, idx: 0
exception(s) occur(s).
------------------------------
The end.

3.function-try-blocks(函数try语句块)

构造函数在进入函数体之前首先执行初始值列表。因为在初始值列表抛出异常时构造函数体内的 try语句块还未生效,所以构造函数体内的catch语句无法处理构造函数初始值列表抛出的异常。
要处理构造函数初始值抛出的异常,必须将构造函数写成函数try语句块(也称为函数测试块)的形式。
function-try-blocks的用法(try放到初始化列表之前,catch语句放到构造函数体外部):

MyClass::MyClass() try : <ctor-initializer> {/*...constructor body... */
}
catch(const std::exception& e) {/*...*/
}

function-try-blocks并不局限于构造函数,也可以用于普通函数。然而,对于普通函数而言没有理由使用function-try-blocks,因为其可以方便地转为函数体内部的try/catch块。相对于构造函数而言,对普通函数使用function-try-blocks的明显不同在于catch语句不需要抛出当前异常或者新的异常,C++运行时也不会自动重新抛出异常。

使用function-try-blocks时,注意事项见如下章节3.1-3.6。

3.1. function-try-blocks的catch语句将捕获任何异常,无论是构造函数体或ctor-initializer直接或间接抛出的异常。

ctor-initializer抛出异常示例:

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception {class Element {public:Element(int val):val_(val){std::cout << "Element ctor called." << std::endl;throw std::runtime_error("Element ctor exception.");}virtual ~Element() = default;protected:int val_;};class Entity {public:Entity(int val);~Entity() noexcept(true){std::cout << "Entity dtor called.\n";}private:Element ele_;};Entity::Entity(int val) try : ele_(val){std::cout << "Entity ctor called.\n";//throw std::runtime_error("Entity ctor exception.");}catch(const std::exception& e) {std::cout << "function-try-block caught: " << e.what() << std::endl;throw std::runtime_error("Exception occurs.");}auto main() -> int {std::cout << "testing exception_function_try_blocks..." << std::endl;try{Entity entity(3);}catch(const std::exception& e) {std::cout << "main() caught: " << e.what() << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

输出:

testing exception_function_try_blocks...
Element ctor called.
function-try-block caught: Element ctor exception.
main() caught: Exception occurs.
------------------------------

构造函数体抛出异常示例:

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception {class Element {public:Element(int val):val_(val){std::cout << "Element ctor called." << std::endl;//throw std::runtime_error("Element ctor exception.");}virtual ~Element() = default;protected:int val_;};class Entity {public:Entity(int val);~Entity() noexcept(true){std::cout << "Entity dtor called.\n";}private:Element ele_;};Entity::Entity(int val) try : ele_(val){std::cout << "Entity ctor called.\n";throw std::runtime_error("Entity ctor exception.");}catch(const std::exception& e) {std::cout << "function-try-block caught: " << e.what() << std::endl;throw std::runtime_error("Exception occurs.");}auto main() -> int {std::cout << "testing exception_function_try_blocks..." << std::endl;try{Entity entity(3);}catch(const std::exception& e) {std::cout << "main() caught: " << e.what() << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

输出:

testing exception_function_try_blocks...
Element ctor called.
Entity ctor called.
function-try-block caught: Entity ctor exception.
main() caught: Exception occurs.
------------------------------

3.2. function-try-blocks的catch语句必须重新抛出当前异常或者抛出一个新的异常。如果function-try-blocks的catch语句没有这么做,运行时将自动重新抛出当前异常。

function-try-blocks的catch语句未重新抛出异常,运行时自动抛出当前异常示例:

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception {class Element {public:Element(int val):val_(val){std::cout << "Element ctor called." << std::endl;throw std::runtime_error("Element ctor exception.");}virtual ~Element() = default;protected:int val_;};class Entity {public:Entity(int val);~Entity() noexcept(true){std::cout << "Entity dtor called.\n";}private:Element ele_;};Entity::Entity(int val) try : ele_(val){std::cout << "Entity ctor called.\n";//throw std::runtime_error("Entity ctor exception.");}catch(const std::exception& e) {std::cout << "function-try-block caught: " << e.what() << std::endl;//throw std::runtime_error("Exception occurs.");}auto main() -> int {std::cout << "testing exception_function_try_blocks..." << std::endl;try{Entity entity(3);}catch(const std::exception& e) {std::cout << "main() caught: " << e.what() << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

输出:

testing exception_function_try_blocks...
Element ctor called.
function-try-block caught: Element ctor exception.
main() caught: Element ctor exception.
------------------------------

3.3. 当function-try-blocks的catch语句捕获了一个function-try-blocks内的异常时,构造函数已经构建的所有对象都会在执行catch语句之前销毁。

示例:

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception {class Foo {public:Foo(){std::cout << "Foo ctor called.\n";}~Foo(){std::cout << "Foo dtor called.\n";}       };class Bar {public:Bar(){std::cout << "Bar ctor called.\n";}~Bar(){std::cout << "Bar dtor called.\n";}     };class Element {public:Element(int val): foo_(), val_(val){std::cout << "Element ctor called." << std::endl;//throw std::runtime_error("Element ctor exception.");}virtual ~Element() = default;protected:int val_;Foo foo_;};class Entity {public:Entity(int val);~Entity() noexcept(true){std::cout << "Entity dtor called.\n";}private:// ele_在bar_之前,因此先构造ele_,再构造bar_Element ele_;Bar bar_;};Entity::Entity(int val) try : bar_(), ele_(val){std::cout << "Entity ctor called.\n";throw std::runtime_error("Entity ctor exception.");}catch(const std::exception& e) {std::cout << "Entering Entity's function-try-block......\n";std::cout << "function-try-block caught: " << e.what() << std::endl;throw std::runtime_error("Exception occurs.");}auto main() -> int {std::cout << "testing exception_function_try_blocks..." << std::endl;try{Entity entity(3);}catch(const std::exception& e) {std::cout << "main() caught: " << e.what() << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

输出:

testing exception_function_try_blocks...
Foo ctor called.
Element ctor called.
Bar ctor called.
Entity ctor called.
Bar dtor called.
Foo dtor called.
Entering Entity's function-try-block......
function-try-block caught: Entity ctor exception.
main() caught: Exception occurs.
------------------------------

3.4. 对于function-try-blockcatch语句内部的对象,不应该访问其成员变量。

以下示例说明catch语句内部的对象可以访问其成员变量。但建议不这么做。

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception_function_try_blocks {class Foo {public:Foo(){std::cout << "Foo ctor called.\n";}virtual ~Foo(){std::cout << "Foo dtor called.\n";}       };class Bar {public:Bar(){std::cout << "Bar ctor called.\n";}virtual ~Bar(){std::cout << "Bar dtor called.\n";}     };class Element {public:Element(int val): foo_(), val_(val){std::cout << "Element ctor called." << std::endl;throw std::runtime_error("Element ctor exception.");}virtual ~Element() = default;int getVal() const noexcept{return val_;}protected:int val_;Foo foo_;};class Entity {public:Entity(int val);virtual ~Entity() noexcept(true){std::cout << "Entity dtor called.\n";}private:// ele_在bar_之前,因此先构造ele_,再构造bar_Element ele_;Bar bar_;};Entity::Entity(int val) try : bar_(), ele_(val){std::cout << "Entity ctor called.\n";//throw std::runtime_error("Entity ctor exception.");}catch(const std::exception& e) {std::cout << "Entering Entity's function-try-block......\n";std::cout << "function-try-block caught: " << e.what() << std::endl;std::cout << "ele_.getVal() = " << ele_.getVal() << std::endl;   // 输出3throw std::runtime_error("Exception occurs.");}auto main() -> int {std::cout << "testing exception_function_try_blocks..." << std::endl;try{Entity entity(3);}catch(const std::exception& e) {std::cout << "main() caught: " << e.what() << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

输出:

__cplusplus: 199711
testing exception_function_try_blocks...
Foo ctor called.
Element ctor called.
Foo dtor called.
Entering Entity's function-try-block......
function-try-block caught: Element ctor exception.
ele_.getVal() = 3
main() caught: Exception occurs.
------------------------------
The end.

3.5. 对于对于function-try-block中的catch语句而言,其中包含的函数不能使用return关键字返回值。构造函数与此无关,因为构造函数没有返回值。

#pragma once#include <iostream>
#include <stdexcept>namespace test_exception_function_try_blocks {class Foo {public:Foo(){std::cout << "Foo ctor called.\n";}virtual ~Foo(){std::cout << "Foo dtor called.\n";}       };class Bar {public:Bar(){std::cout << "Bar ctor called.\n";}virtual ~Bar(){std::cout << "Bar dtor called.\n";}     };class Element {public:Element(int val): foo_(), val_(val){std::cout << "Element ctor called." << std::endl;throw std::runtime_error("Element ctor exception.");}virtual ~Element() = default;int getVal() const noexcept{return val_;}protected:int val_;Foo foo_;};class Entity {public:Entity(int val);virtual ~Entity() noexcept(true){std::cout << "Entity dtor called.\n";}private:// ele_在bar_之前,因此先构造ele_,再构造bar_Element ele_;Bar bar_;};Entity::Entity(int val) try : bar_(), ele_(val){std::cout << "Entity ctor called.\n";//throw std::runtime_error("Entity ctor exception.");}catch(const std::exception& e) {std::cout << "Entering Entity's function-try-block......\n";std::cout << "function-try-block caught: " << e.what() << std::endl;return;  // [ERROR]Visual Studio 15 2017, error C2176: 不能在与构造函数关联的函数 try 块的处理程序中使用 return 语句//        MinGW Makefiles, error: cannot return from a handler of a function-try-block of a constructorthrow std::runtime_error("Exception occurs.");}auto main() -> int {std::cout << "testing exception_function_try_blocks..." << std::endl;try{Entity entity(3);}catch(const std::exception& e) {std::cout << "main() caught: " << e.what() << std::endl;}std::cout << "------------------------------" << std::endl;return 0;}
}

此示例编译出错,详见注释。

3.6 鉴于以上限制,构造函数的function-try-block只在少数情况下有用

  • 将ctor-initializer抛出的异常转换为其它异常;
  • 将信息记录到日志文件。

4.析构函数中的错误

必须在析构函数内部处理析构函数引起的所有错误,不应该让析构函数抛出任何异常。
如果析构函数需要执行某个可能抛出异常的操作,则该操作应该被放置在一个try语句块中,并且在析构函数内部得到处理。
在实际的编程中,因为析构函数仅仅是释放资源,所以它不大可能抛出异常。所有标准库类型都能确保它们的析构函数不会引发异常。

在栈展开的过程中,运行类类型的局部对象的析构函数。因为这些析构函数是自动执行的,所以它们不应该抛出异常。一旦在栈展开的过程中析构函数抛出了异常,并且析构函数自身没能捕获到该异常,则程序将被终止。

5.noexcept

5.1 noexcept有两层含义

1.当跟在函数参数列表后面时它是异常说明符;
2.当作为noexcept异常说明的bool实参出现时,它是一个运算符。

void recoup(int) noexcept;         // 不会抛出异常
void recoup(int) noexcept(true);   // 不会抛出异常,与上句的等价写法
void alloc(int);                   // 可能抛出异常
void alloc(int) noexcept(false);   // 可能抛出异常,与上句的等价写法

5.2 noexcept异常说明

预先知道函数不会抛出异常的好处:
1.有助于简化调用该函数的代码;
2.如果编译器确认函数不会抛出异常,它就能执行某些特殊的优化操作,而这些优化操作并不适用于可能出错的代码。

5.3 noexcept用于异常说明符时出现的位置

1.noexcept要么出现在函数的所有声明语句和定义语句中,要么一次也不出现;
2.noexcept应该在函数的尾置返回类型之前;
3.放在构造函数的初始化列表之前;
4.在成员函数中,noexcept说明符需要跟在const及引用限定符之后,而在finaloverride或虚函数的=0之前;
5.在typedef或类型别名中则不能出现noexcept。

5.4违反异常说明

一般编译器并不会在编译时检查noexcept说明,如果一个函数在说明了noexcept的同时又含有throw语句或者调用了可能抛出异常的其它函数,编译器将顺利编译通过,并不会因为这种违反异常说明的情况而报错(不排除个别编译器会对这种用法提出警告)。
// 尽管该函数明显违反了异常说明,但它仍然可以顺利编译通过

void f() noexcept {     // 承诺不会抛出异常throw exception();  // 违反了异常说明
}

因此可能出现这样一种情况:尽管函数声明了不会抛出异常,但实际上还是抛出了,一旦一个noexcept函数抛出了异常,程序就会调用ternimate以确保遵守不在运行时抛出异常的承诺。
示例:

#include <iostream>
#include <stdexcept>namespace test_exception {auto func1() noexcept(true) -> void {std::cout << "func1()" << std::endl;throw std::exception();   // [Visual Studio 15 2017] warning C4297: “test_exception::func1”: 假定函数不引发异常,但确实发生了// [MinGW Makefiles] warning: 'throw' will always call 'terminate'}auto main() -> int {std::cout << "testing exception..." << std::endl;func1();   // [Visual Studio 15 2017]运行时会崩溃,提示:abort()has been calledstd::cout << "------------------------------" << std::endl;return 0;}
}

5.5 什么时候使用noexcept?

1.确认函数不会抛出异常;
2.根本不知道如何处理异常。

5.5 noexcept运算符是一个一元运算符

noexcept运算符返回值是一个bool类型的右值常量表达式,用于表示给定的表达式是否会抛出异常。(和sizeof类似,noexcept也不会求其运算对象的值。)
用法:noexcept(e),当e调用的所有函数都做了不抛出说明且e本身不含有throw语句时,上述表达式为true,否则noexcept(e)返回false
例如:因为声明recoup时使用了noexcept说明符,所以noexcept(recout(i))返回true

void f() noexcept(noexcept(g()));  // f和g的异常说明一致,如果函数g承诺了不会抛出异常,则f也不会抛出异常,// 如果g没有异常说明符,或g虽然有异常说明符但是运行抛出异常,则f也可能抛出异常

示例:

#include <iostream>
#include <stdexcept>
#include <typeinfo>namespace test_exception {auto func1() noexcept(true) -> void {std::cout << "func1()" << std::endl;throw std::exception();   // [Visual Studio 15 2017] warning C4297: “test_exception::func1”: 假定函数不引发异常,但确实发生了// [MinGW Makefiles] warning: 'throw' will always call 'terminate'}auto func2(int i) noexcept(true) -> void {std::cout << "func2()" << std::endl;}auto func3(int i) noexcept(false) -> void {std::cout << "func3()" << std::endl;throw std::exception();}auto func4(int i) -> void {std::cout << "func3()" << std::endl;}void (*pf1)(int) noexcept(true);void (*pf2)(int) noexcept(false);auto main() -> int {std::cout << "testing exception..." << std::endl;std::cout << "type(func1): " << typeid(func1).name() << std::endl;std::cout << "type(func1()): " << typeid(func1()).name() << std::endl;std::cout << "type(func2): " << typeid(func2).name() << std::endl;std::cout << "type(func2()): " << typeid(func2(0)).name() << std::endl;std::cout << "type(func3): " << typeid(func3).name() << std::endl;std::cout << "type(func3()): " << typeid(func3(0)).name() << std::endl;std::cout << "type(func4): " << typeid(func4).name() << std::endl;std::cout << "type(func4()): " << typeid(func4(0)).name() << std::endl;// 写成函数调用的方式才能正确获取到函数是:noexcept(true)或noexcept(false)std::cout << "noexcept(func1()): " << noexcept(func1()) << std::endl;   // 注意这里要写成函数调用的形式,不要写成noexcept(func1)std::cout << "noexcept(func2(0)): " << noexcept(func2(0)) << std::endl;std::cout << "noexcept(func3(0)): " << noexcept(func3(0)) << std::endl;std::cout << "noexcept(func4(0)): " << noexcept(func4(0)) << std::endl;std::cout << "3: " << noexcept(3) << std::endl;// 如果写成了函数名的形式则始终返回:truestd::cout << "noexcept(func1): " << noexcept(func1) << std::endl;std::cout << "noexcept(func2): " << noexcept(func2) << std::endl;std::cout << "noexcept(func3): " << noexcept(func3) << std::endl;std::cout << "noexcept(func4): " << noexcept(func4) << std::endl;//func1();   // [Visual Studio 15 2017]运行时会崩溃,提示:abort()has been calledpf1 = func2;// pf1 = func3; // error C2440: “=”: 无法从“void (__cdecl *)(int) noexcept(false)”转换为“void (__cdecl *)(int) noexcept”pf2 = func2;pf2 = func3;std::cout << "------------------------------" << std::endl;return 0;}
}

以上程序输出:

testing exception...
type(func1): void __cdecl(void) noexcept
type(func1()): void
type(func2): void __cdecl(int) noexcept
type(func2()): void
type(func3): void __cdecl(int)
type(func3()): void
type(func4): void __cdecl(int)
type(func4()): void
noexcept(func1()): 1
noexcept(func2(0)): 1
noexcept(func3(0)): 0
noexcept(func4(0)): 0
3: 1
noexcept(func1): 1
noexcept(func2): 1
noexcept(func3): 1
noexcept(func4): 1
------------------------------

5.6 异常说明与指针、虚函数

尽管noexcept说明符不属于函数类型的一部分,但函数的异常说明仍然会影响函数的使用。
如果为某个指针做了不抛出异常的声明,则该指针将只能指向不抛出异常的函数;如果显式或隐式地说明了指针可能抛出异常,则该指针可以指向任何函数,即使是承诺了不抛出异常的函数也可以。

// recoup和pfunc1都承诺不会抛出异常
void (*pfunc1)(int) noexcept = reoup;
void (*pfunc2)(int) = recoup;  // 正确,recoup不会抛出异常,pfunc2可能抛出异常pfunc1 = alloc;    // 错误,alloc可能抛出异常,但pfunc1说明了其不会抛出异常
pfunc2 = alloc;    // pfunc2和alloc都可能抛出异常

如果一个虚函数承诺了它不会抛出异常,则后续派生出来的虚函数也必须做出同样的承诺;如果基类的虚函数运行抛出异常,则派生类的对应函数既可以运行抛出异常,也可以不允许抛出异常。
示例:

#include <stdexcept>
namespace test_exception {class Base{public:Base() = default;virtual ~Base() = default;virtual void func1(int i) noexcept(true){}virtual void func2(int i) noexcept(false){}};class DerivedA: public Base {public:        DerivedA() = default;virtual ~DerivedA() = default;virtual void func1(int i) noexcept(true) override{}  // [right]virtual void func2(int i) noexcept(true) override{}  // [right]};class DerivedB: public Base {public:   DerivedB() = default;virtual ~DerivedB() = default;virtual void func1(int i) noexcept(false) override{} // [wrong]// [Visual Studio 15 2017]error C2694: “void test_exception::DerivedB::func1(int) noexcept(false)”: 重写虚函数的限制性异常规范比基类虚成员函数“void test_exception::Base::func1(int) noexcept”少// [MinGW Makefiles] error: looser exception specification on overriding virtual function 'virtual void test_exception::DerivedB::func1(int) noexcept (false)'virtual void func2(int i) noexcept(false) override{} // [right]};auto main() -> int {std::cout << "testing exception..." << std::endl;std::cout << "------------------------------" << std::endl;return 0;}
}

Reference

1.Marc Gregoire, Nicholas A. Solter, Scott J. Kleper. C++高级编程(第2版). 清华大学出版社,2012.(P301-P308)
2. Stanley B. Lippman, Josée Lajoie, Barbara E. Moo. C++ Primer 中文版(第5版).电子工业出版社,2013.(P690)

三谈exception——错误处理相关推荐

  1. 从“马云三谈996”窥视中国企业家的内心世界

    http://www.ftchinese.com/story/001082356 马云针对996讲了几句之后,反响不太好,于是又讲了几句,反响还是不太好,于是又讲了几句.不知道他还会不会再讲,但是这三 ...

  2. 魏永明: 三谈操作系统

    2012年,借着阿里云操作系统被谷歌打压的事件,我写了有关操作系统的第一篇文章:<"自主"操作系统--为什么及如何>(见本文末尾原文链接).2015年,是我比较闲的时候 ...

  3. 诡异的The inferior stopped because it triggered an exception错误

    问题描述 一个很简单的函数: void do_print(const char *format_str,int arg) {std::map<std::string,std::string> ...

  4. 第三章 SQL错误信息

    文章目录 第三章 SQL错误信息 `SQLCODE` `0`和`100` `SQLCODE -400` 检索`SQL`消息文本 第三章 SQL错误信息 下表列出了SQL数字错误代码及其错误消息.这些代 ...

  5. ETSI TR101 290监测的三种级别错误接收端现象

    对于码流分析仪所提供ETSI TR101 290监测的三种级别错误,接收端将会出现如下现象. 级别 错误类型 接收端现象 一 级 错 误 同步丢失错 黑屏.静帧和马赛克.画面不流畅现象 同步字节错 黑 ...

  6. 三谈属性动画——Keyframe以及ViewPropertyAnimator

    Android动画和Transition系列文章 初识属性动画--使用Animator创建动画 再谈属性动画--介绍以及自定义Interpolator插值器 三谈属性动画--Keyframe以及Vie ...

  7. opencv imshow函数报cv::exception错误,以及sift算法的使用问题

    记录遇到的小问题 刚发布的就不见了,活生生的不见了,难道是我吐槽百度出来的博客很多都是抄的同一篇? 简略的描述一下问题(小白使用,大佬就不用看了) opencv版本:4.0.0,使用vs2015编译 ...

  8. 三谈ChatGPT(ChatGPT可以解决问题的90%)

    这是我第三次谈ChatGPT,前两篇主要谈了ChatGPT的概念,之所以火的原因和对人们的影响,以及ChatGPT可能存在的安全风险和将面临的监管问题.这一篇主要讲讲ChatGPT的场景和处理问题的逻 ...

  9. python爬虫超时重试_Python爬虫实例(三):错误重试,超时处理

    错误重试 错误重试用到的方法之一是:@retry()装饰器html 装饰器实际是一个python函数,它的做用就是为被装饰的函数(或对象)进行装饰.包装,可让被装饰的函数(或对象)在不须要作任何代码改 ...

最新文章

  1. 【BZOJ】1610: [Usaco2008 Feb]Line连线游戏(几何)
  2. 极光 php 自定义消息,laravel框架使用极光推送消息操作示例
  3. LeetCode Arranging Coins
  4. 《CCNP ROUTE (642-902 )认证考试指南》一1.2 将考试主题与典型网络工程师的工作关联起来...
  5. getLastSql()用法
  6. docker概念:用Dockerfile生成Image
  7. 黑苹果找不到触控板_苹果App内测找不到苹果企业签名怎么办?
  8. Detection and Classification of Acoustic Scenes and Events(DCASE2013详细介绍)
  9. 【渝粤教育】广东开放大学 PHP动态网站设计 形成性考核 (48)
  10. mysql多客户端数据不同步_一种多终端设备上的数据同步方法
  11. One of the two will be used. Which one is undefined.
  12. 如何修改MySQL已有表的字符集
  13. AnnotationConfigBeanDefinitionParser are only available on JDK 1.5 and higher
  14. 如何解决Mac启动盘已满的问题?MacBooster帮你清理20种垃圾文件!
  15. android显示emoji,android兼容emoji显示以及检测是否支持emoji
  16. Android数据库设计
  17. 前篇:1.公共技术点之面向对象六大原则
  18. 在d盘创建文件夹,里面有aaa.txt/bbb.txt/ccc.txt,然后遍历出aaa文件夹下的文件(新手用于记录每天的作业)...
  19. 字节一面:“为什么网络要分层?每一层的职责、包含哪些协议?”
  20. zabbix使用web界面监控本机

热门文章

  1. 什么是软件测试?软件测试和研发的区别
  2. Gateway网关基础配置
  3. Js如何截取字符串最后一位
  4. [Greenfoot中文教程] 01 - Greenfoot初体验
  5. Android 铃声多媒体音量、静音、震动(附源码)
  6. 智慧校园平台源码 智慧班牌源码 人脸识别技术 电子班牌源码 家校互联小程序源码
  7. LattePanda的Ubuntu虚拟机里安装评测OpenVINO和Intel计算棒NCS2
  8. HTTP Status Codes/HTTP状态码
  9. 实验一网络扫描与网络侦察
  10. linux系统可以装win10吗,教大家1个能在win10安装运行Linux系统的方法