C++—Exceptions and type conversions, endian storage, swapping two numbers without using extra space

abnormal

Common exceptions include: the array subscript is out of bounds, the divisor is 0 during division calculation, and the space is insufficient when dynamically allocating space.

try,throw,catch


#include <iostream>
using namespace std;
int main()
{
    
    
    double m = 1, n = 0;
    try {
    
    
        cout << "before dividing." << endl;
        if (n == 0)
            throw - 1;  //抛出int型异常
        else if (m == 0)
            throw - 1.0;  //拋出 double 型异常
        else
            cout << m / n << endl;
        cout << "after dividing." << endl;
    }
    catch (double d) {
    
    
        cout << "catch (double)" << d << endl;
    }
    catch (...) {
    
    
        cout << "catch (...)" << endl;
    }
    cout << "finished" << endl;
    return 0;
}
//运行结果
//before dividing.
//catch (...)
//finished

List of exception declarations for functions

int fun() throw(int,double,A,B,C){
    
    ...};

You can point out the list of exceptions that can be thrown when the function is declared and defined. If throw is empty, it means that no exception will be thrown. If there is no throw, any exception may be thrown.

C++ standard exception class

insert image description here

bad_typeid

If its operand is a polymorphic class pointer, and the value of the pointer is NULL, this exception will be thrown.

#include <iostream>
#include <typeinfo>
using namespace std;

class A{
    
    
public:
  virtual ~A();
};
 
using namespace std;
int main() {
    
    
	A* a = NULL;
	try {
    
    
  		cout << typeid(*a).name() << endl; // Error condition
  	}
	catch (bad_typeid){
    
    
  		cout << "Object is NULL" << endl;
  	}
    return 0;
}
//运行结果:bject is NULL

bad_cast

When using dynamic_cast to cast a polymorphic base class object or reference to a derived class reference, if the conversion is unsafe, this exception will be thrown.

bad_alloc

not enough memory

out_of_range

Subscript out of bounds.

How C++ handles multiple exceptions

The basic idea of ​​exception handling: if an exception is found during the execution of a function, it is not necessary to handle it immediately in this function, but to throw the exception, so that the caller of the function can directly or indirectly deal with this problem. The C++ exception handling mechanism consists of 3 modules: try (check), throw (throw), and catch (catch). The format of the statement that throws an exception is: throw expression; if an exception is found in the program segment in the try block, an exception is thrown .

try  {
    
      可能抛出异常的语句;(检查) try 
{
    
     
可能抛出异常的语句;(检查) 
} 
catch(类型名[形参名]//捕获特定类型的异常 
{
    
     
//处理1; 
} 
catch(类型名[形参名]//捕获特定类型的异常 
{
    
     
//处理2; 
} 
catch(…)//捕获所有类型的异常 
{
    
     
}

type conversion

reinterpret_cast

reinterpret_cast<type-id> (expression), type-id must be a pointer, reference, arithmetic type, function pointer or member pointer, which can be used for forced conversion between types.

const_cast

const_cast<type_id> (expression), the usage is as follows:

  • A const pointer is converted to a non-const pointer and still points to the original object
  • const references are converted to non-const references and still point to the original object
  • const_cast is generally used to modify the bottom pointer, such as the form of const char*p

static_cast

static_cast < type-id > (expression)
This operator converts an experssion to a type-id type, but there is no runtime type checking to ensure conversion safety. There are mainly the following uses:

  • Conversion of references or pointers between base and derived classes in a class hierarchy
  • Used for conversion between basic data types, such as converting int to char, the security needs to be guaranteed by the developer
  • converts a null pointer to a null pointer of the target type
  • Convert any type of expression to void type

Note: stati_cast cannot convert the const, volatile, or _unaligned attributes of expression

dynamic_cast

  • dynamic_cast <type-id> (expression)There is type checking. type-id must be a pointer to a class, a reference to a class, or void*.
  • If type-id is a pointer-like type, then expression must also be a pointer, and if type-id is a reference, then expression must also be a reference
  • The dynamic_cast operator can determine the real type at execution time, that is to say **expression must be a polymorphic type. If the downcast is safe, the operator will return a properly cast pointer. If it is not safe, the operator will return Returns a null pointer.
  • It is mainly used for up-conversion and down-conversion between class hierarchies , and can also be used for cross-conversion between classes .

The difference between static_cast and dynamic_cast for uplink and downlink conversion

  • It is safe for up-conversion; for down-conversion, dynamic_cast will perform RTTI and has the function of type checking, so down-conversion is safe; while static_cast will not perform RTTI, so it is not safe.

Code reference Axiu's study notes

#include <bits/stdc++.h>
using namespace std;

class Base
{
    
    
public:
	Base() :b(1) {
    
    }
	virtual void fun() {
    
    };
	int b;
};

class Son : public Base
{
    
    
public:
	Son() :d(2) {
    
    }
	int d;
};

int main()
{
    
    
	int n = 97;

	//reinterpret_cast
	int *p = &n;
	//以下两者效果相同
	char *c = reinterpret_cast<char*> (p); 
	char *c2 =  (char*)(p);
	cout << "reinterpret_cast输出:"<< *c2 << endl;
	//const_cast
	const int *p2 = &n;
	int *p3 = const_cast<int*>(p2);
	*p3 = 100;
	cout << "const_cast输出:" << *p3 << endl;
	
	Base* b1 = new Son;
	Base* b2 = new Base;

	//static_cast
	Son* s1 = static_cast<Son*>(b1); //同类型转换
	Son* s2 = static_cast<Son*>(b2); //下行转换,不安全
	cout << "static_cast输出:"<< endl;
	cout << s1->d << endl;
	cout << s2->d << endl; //下行转换,原先父对象没有d成员,输出垃圾值

	//dynamic_cast
	Son* s3 = dynamic_cast<Son*>(b1); //同类型转换
	Son* s4 = dynamic_cast<Son*>(b2); //下行转换,安全
	cout << "dynamic_cast输出:" << endl;
	cout << s3->d << endl;
	if(s4 == nullptr)
		cout << "s4指针为nullptr" << endl;
	else
		cout << s4->d << endl;
	
	
	return 0;
}
//输出结果
//reinterpret_cast输出:a
//const_cast输出:100
//static_cast输出:
//2
//-33686019
//dynamic_cast输出:
//2
//s4指针为nullptr

endian storage

What is endian storage

  • Big endian: the high byte is placed at the low address
  • Little endian: the low byte is placed at the low address

How to determine the big and small endian storage

  • cast
#include <iostream>
using namespace std;
int main()
{
    
    
    int a = 0x1234;
    //由于int和char的长度不同,借助int型转换成char型,只会留下低地址的部分
    char c = (char)(a);
    if (c == 0x12)
        cout << "big endian" << endl;
    else if(c == 0x34)
        cout << "little endian" << endl;
}

  • union union
#include <iostream>
using namespace std;
//union联合体的重叠式存储,endian联合体占用内存的空间为每个成员字节长度的最大值
union endian
{
    
    
    int a;
    char ch;
};
int main()
{
    
    
    endian value;
    value.a = 0x1234;
    //a和ch共用4字节的内存空间
    if (value.ch == 0x12)
        cout << "big endian"<<endl;
    else if (value.ch == 0x34)
        cout << "little endian"<<endl;
}

A union is a data structure that allows different types of data to be stored in the same memory location. Different members in the union share the same memory space, but only one of them can be stored at the same time. This means that the members in the union overlap in memory because they share the same storage space.

How to swap two numbers without using extra space?


1)  算术

x = x + y;
 y = x - y;

x = x - y; 

2)  异或
//两个数相等的时候不能这么用
x = x^y;// 只能对int,char..
 y = x^y;
 x = x^y;


Guess you like

Origin blog.csdn.net/qaaaaaaz/article/details/131264503