C++中static_cast/const_cast/dynamic_cast/reinterpret_cast的区别和使用

2023-10-27

C风格的强制转换较简单,如将float a转换为int b,则可以这样:b = (int)a,或者b=int(a)。

C++类型转换分为隐式类型转换和显示类型转换。

隐式类型转换又称为标准转换,包括以下几种情况:

(1)、算术转换:在混合类型的算术表达式中,最宽的数据类型成为目标转换类型;

(2)、一种类型表达式赋值给另一种类型的对象:目标类型是被赋值对象的类型;

(3)、将一个表达式作为实参传递给函数调用,此时形参和实参类型不一致:目标转换类型为形参的类型;

(4)、从一个函数返回一个表达式,表达式类型与返回类型不一致:目标转换类型为函数的返回类型。

显示类型转换被称为强制类型转换(cast)。

C++提供了四种强制类型转换形式:static_cast、const_cast、dynamic_cast、reinterpret_cast.每一种适用于特定的场合。

static_cast语法:static_cast<type-id>(expression)

static_cast:仅根据表达式中存在的类型,将expression转换为type-id类型。此运算符可用于将指向基类的指针转换为指向派生类的指针等操作。此类转换并非始终安全。

通常使用 static_cast 转换数值数据类型,例如将枚举型转换为整型或将整型转换为浮点型,而且你能确定参与转换的数据类型。 static_cast转换安全性不如dynamic_cast转换,因static_cast不执行运行时类型检查,而dynamic_cas执行该检查。对不明确的指针的 dynamic_cast将失败,而static_cast的返回结果看似没有问题,这是危险的。尽管 dynamic_cast转换更加安全,但是dynamic_cast只适用于指针或引用,而且运行时类型检查也是一项开销。dynamic_cast 和static_cast运算符可以在整个类层次结构中移动指针。然而,static_cast完全依赖于转换语句提供的信息,因此可能不安全。

static_cast可以反向执行隐式转换,可用于任何隐式允许的转换类型,而在这种情况下结果是不确定的。这需要程序员来验证static_cast转换的结果是否安全。

static_cast可用于将int转换为char。但是,得到的char可能没有足够的位来保存整个int值。同样,这需要程序员来验证static_cast转换的结果是否安全。

static_cast运算符还可用于执行任何隐式转换,包括标准转换和用户定义的转换。

static_cast 运算符可以将整数值显式转换为枚举类型。如果整型值不在枚举值的范围内,生成的枚举值是不确定的。

static_cast运算符将null指针值转换为目标类型的null指针值。

任何表达式都可以通过static_cast运算符显式转换为void类型。目标void类型可以选择性地包含const、volatile或__unaligned特性。

static_cast运算符无法转换掉const、volatile或 __unaligned特性。

只有在确信代码将正常运行的时候,在性能关键代码中使用 static_cast。如果必须在发布模式下使用static_cast,请在调试版本中用 safe_cast(C++ 组件扩展)替换它以确保成功。

任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。

const_cast语法:const_cast<type-id>(expression)

const_cast:从类中移除const、volatile和__unaligned特性。

指向任何对象类型的指针或指向数据成员的指针可显式转换为完全相同的类型(const、volatile 和 __unaligned 限定符除外)。对于指针和引用,结果将引用原始对象。对于指向数据成员的指针,结果将引用与指向数据成员的原始(未强制转换)的指针相同的成员。根据引用对象的类型,通过生成的指针、引用或指向数据成员的指针的写入操作可能产生未定义的行为。

不能使用const_cast运算符直接重写常量变量的常量状态。

const_cast运算符将null指针值转换为目标类型的null指针值。

dynamic_cast语法:dynamic_cast<type-id>(expression)

dynamic_cast:type-id必须是一个指针或引用到以前已定义的类类型的引用或“指向 void的指针”。如果type-id是指针,则expression的类型必须是指针,如果type-id是引用,则为左值。

在托管代码中的 dynamic_cast的行为中有两个重大更改:(1)、为指针的dynamic_cast对指向装箱的枚举的基础类型的指针将在运行时失败,则返回0而不是已转换的指针。(2)、dynamic_cast 将不再引发一个异常,当type-id是指向值类型的内部指针,则转换在运行时失败。该转换将返回0指示运行值而不是引发。

如果type-id是指向expression的明确的可访问的直接或间接基类的指针,则结果是指向type-id类型的唯一子对象的指针。

如果type-id为void*,则做运行时进行检查确定expression的实际类型。结果是指向byexpression的完整的对象的指针。

如果type-id不是 void*,则做运行时进行检查以确定是否由expression指向的对象可以转换为由type-id指向的类型。如果expression类型是type-id类型的基类,则做运行时检查来看是否expression确实指向type-id类型的完整对象。如果为true,则结果是指向type-id类型的完整对象的指针。

dynamic_cast运算符还可以使用执行“相互转换”。使用同一个类层次结构可能进行指针转换。

当使用dynamic_cast时,如果expression无法安全地转换成类型type-id,则运行时检查会引起变换失败。

指针类型的非限定转换的值是null指针。引用类型的非限定转换会引发bad_cast异常。

dynamic_cast支持运行时类型识别。

reinterpret_cast语法:reinterpret_cast<type-id>(expression)

reinterpret_cast:允许将任何指针转换为任何其他指针类型。也允许将任何整数类型转换为任何指针类型以及反向转换。

滥用reinterpret_cast运算符可能很容易带来风险。除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。

reinterpret_cast运算符可用于char*到int*或One_class*到Unrelated_class*之类的转换,这本身并不安全。

reinterpret_cast的结果不能安全地用于除强制转换回其原始类型以外的任何用途。在最好的情况下,其他用途也是不可移植的。

reinterpret_cast运算符不能丢掉const、volatile或__unaligned特性。

reinterpret_cast运算符将null指针值转换为目标类型的null指针值。

reinterpret_cast的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。

reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。reinterpret_cast本质上依赖机器。要想安全地使用reinterpret_cast必须对涉及的类型和编译器实现转换的过程都非常了解。

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases,explicitly stating static_cast isn't necessary, but it's important to note that the T(something) syntax is equivalent to (T)something and should be avoided(more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual inheritance. It does not do checking,however, and it is undefined behavior to static_cast down a hierarchy to a type that isn't actually the type of the object.

const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly const value is only undefined if the original variable is const; if you use it to take the const off a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object,such as to call a member function overload.

const_cast also works similarly on volatile, though that's less common.

dynamic_cast is almost exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards -- you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can't, it will return nullptr in the case of a pointer, or throw std::bad_cast in the case of a reference.

dynamic_cast has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual inheritance. It also can only go through public inheritance - it will always fail to travel through protected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.

reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another - such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things.Largely, the only guarantee you get with reinterpret_cast is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type).There are a number of conversions that reinterpret_cast cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of an aligned pointer.

C casts are casts using (type)object or type(object). A C-style cast is defined as the first of the following which succeeds:(1)、const_cast; (2)、static_cast(though ignoring access restrictions); (3)、static_cast (see above), then const_cast; (4)、reinterpret_cast; (5)、reinterpret_cast, then const_cast。

It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast,and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed or reinterpret_cast will fail. Even then,consider the longer, more explicit option.

C-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.

测试代码如下:

static_cast.hpp:

#ifndef FBC_MESSY_TEST_STATIC_CAST_HPP_
#define FBC_MESSY_TEST_STATIC_CAST_HPP_

#include <iostream>

// reference: https://msdn.microsoft.com/zh-cn/library/c36yw7x9.aspx
class B1 {
public:
	virtual void Test(){}
};

class D1 : public B1 {};

class CCTest {
public:
	void setNumber(int);
	void printNumber() const;
private:
	int number;
};

class B2 { };
class C2 : public B2 { };
class D2 : public C2 { };

class A3 { virtual void f(); };
class B3 { virtual void f(); };

class B4 { virtual void f(); };
class D4 : public B4 { virtual void f(); };

// Returns a hash code based on an address
unsigned short Hash(void *p);

void test_static_cast1();
void test_static_cast2(B1* pb, D1* pd);
void test_static_cast3(B1* pb);
void test_static_cast4();
void test_static_cast5();
void test_static_cast6();
void test_static_cast7();
void test_static_cast8();
void test_static_cast9();
void test_static_cast10();

#endif // FBC_MESSY_TEST_STATIC_CAST_HPP_

static_cast.cpp:

#include "static_cast.hpp"
#include <iostream>

void CCTest::setNumber(int num) { number = num; }

void CCTest::printNumber() const {
	std::cout << "\nBefore: " << number;
	//this 指针的数据类型为 const CCTest *。
	//const_cast 运算符会将 this 指针的数据类型更改为 CCTest *,以允许修改成员 number。
	//强制转换仅对其所在的语句中的其余部分持续
	const_cast< CCTest * >(this)->number--;
	std::cout << "\nAfter: " << number;
}

void A3::f()
{

}

void B3::f()
{

}

void B4::f()
{

}

void D4::f()
{

}

unsigned short Hash(void *p) {
	//reinterpret_cast 允许将指针视为整数类型。结果随后将按位移位并与自身进行“异或”运算以生成唯一的索引(具有唯一性的概率非常高)。
	//该索引随后被标准 C 样式强制转换截断为函数的返回类型。
	unsigned int val = reinterpret_cast<unsigned int>(p);
	return (unsigned short)(val ^ (val >> 16));
}

// C风格强制类型转换
void test_static_cast1()
{
	float a = 1.1, b = 1.9;

	int ret1 = (int)a;
	int ret2 = int(b);

	std::cout << ret1 << "    " << ret2 << "    " << std::endl;
}

void test_static_cast2(B1* pb, D1* pd)
{
	//与 dynamic_cast 不同,pb 的 static_cast 转换不执行运行时检查。
	//由 pb 指向的对象可能不是 D 类型的对象,在这种情况下使用 *pd2 会是灾难性的。
	//例如,调用 D 类(而非 B 类)的成员函数可能会导致访问冲突。
	D1* pd2 = static_cast<D1*>(pb);   // Not safe, D can have fields and methods that are not in B.
	B1* pb2 = static_cast<B1*>(pd);   // Safe conversion, D always contains all of B.
}

void test_static_cast3(B1* pb)
{
	//如果 pb 确实指向 D 类型的对象,则 pd1 和 pd2 将获取相同的值。如果 pb == 0,它们也将获取相同的值。
	//如果 pb 指向 B 类型的对象,而非指向完整的 D 类,则 dynamic_cast 足以判断返回零。
	//但是,static_cast 依赖于程序员的断言,即 pb 指向 D 类型的对象,因而只是返回指向那个假定的 D 对象的指针。
	D1* pd1 = dynamic_cast<D1*>(pb);
	D1* pd2 = static_cast<D1*>(pb);
}

void test_static_cast4()
{
	char ch;
	int i = 65;
	float f = 2.5;
	double dbl;

	ch = static_cast<char>(i);   // int to char
	dbl = static_cast<double>(f);   // float to double
	i = static_cast<int>(ch);
}

void test_static_cast5()
{
	CCTest X;
	X.setNumber(8);
	X.printNumber();
}

void test_static_cast6(D2* pd)
{
	//此转换类型称为“向上转换”,因为它将在类层次结构上的指针,从派生的类移到该类派生的类。向上转换是一种隐式转换。
	C2* pc = dynamic_cast<C2*>(pd);   // ok: C is a direct base class pc points to C subobject of pd 
	B2* pb = dynamic_cast<B2*>(pd);   // ok: B is an indirect base class pb points to B subobject of pd
}

void test_static_cast7()
{
	A3* pa = new A3;
	B3* pb = new B3;
	void* pv = dynamic_cast<void*>(pa);// pv now points to an object of type A
	pv = dynamic_cast<void*>(pb);// pv now points to an object of type B
}

void test_static_cast8()
{
	B4* pb = new D4;   // unclear but ok
	B4* pb2 = new B4;

	//此转换类型称为“向下转换”,因为它将在类层次结构下的指针,从给定的类移到该类派生的类。
	D4* pd = dynamic_cast<D4*>(pb);   // ok: pb actually points to a D
	D4* pd2 = dynamic_cast<D4*>(pb2);   // pb2 points to a B not a D
}

void test_static_cast9()
{
	A3* pa = new A3;
	B3* pb = dynamic_cast<B3*>(pa);   // fails at runtime, not safe;B not derived from A
}

void test_static_cast10()
{
	int a[20];
	for (int i = 0; i < 20; i++) {
		std::cout << Hash(a + i) << std::endl;
	}
}

主要参考文献:

1. https://msdn.microsoft.com/zh-cn/library/c36yw7x9.aspx

2. http://en.cppreference.com/w/cpp/language/static_cast 

3. http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used 

GitHubgithub.com/fengbingchun/Messy_Test

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中static_cast/const_cast/dynamic_cast/reinterpret_cast的区别和使用 的相关文章

  • C和C++安全编码笔记:整数安全

    5 1 整数安全导论 整数由包括0的自然数 0 1 2 3 和非零自然数的负数 1 2 3 构成 5 2 整数数据类型 整数类型提供了整数数学集合的一个有限子集的模型 一个具有整数类型的对象的值是附着在这个对象上的数学值 一个具有整数类型的
  • C语言中的弱符号与强符号介绍

    弱符号 Weak symbol 是链接器 ld 在生成ELF Executable and Linkable Format 缩写为ELF 可执行和可链接格式 是一种用于可执行文件 目标文件 共享库和核心转储的标准文件格式 ELF文件有两种索
  • C++中namespace detail或namespace internal的使用

    在很多开源代码中偶尔会使用名字为 detail 或 internal 的命名空间 如OpenCV的modules目录中 有些文件中使用了namespace detail 有些文件中使用了namespace internal 名为detail
  • C++11中std::future的使用

    C 11中的std future是一个模板类 std future提供了一种用于访问异步操作结果的机制 std future所引用的共享状态不能与任何其它异步返回的对象共享 与std shared future相反 std future r
  • C++11容器中新增加的emplace相关函数的使用

    C 11中 针对顺序容器 如vector deque list 新标准引入了三个新成员 emplace front emplace和emplace back 这些操作构造而不是拷贝元素 这些操作分别对应push front insert和p
  • C++11中std::function的使用

    类模版std function是一种通用 多态的函数封装 std function的实例可以对任何可以调用的目标实体进行存储 复制 和调用操作 这些目标实体包括普通函数 Lambda表达式 函数指针 以及其它函数对象等 通过std func
  • 概率论中高斯分布(正态分布)介绍及C++11中std::normal_distribution的使用

    高斯分布 最常用的分布是正态分布 normal distribution 也称为高斯分布 Gaussian distribution 正态分布N x 2 呈现经典的 钟形曲线 的形状 其中中心峰的x坐标由 给出 峰的宽度受 控制 正态分布由
  • C++/C++11中引用的使用

    引用 reference 是一种复合类型 compound type 引用为对象起了另外一个名字 引用类型引用 refer to 另外一种类型 通过将声明符写成 d的形式来定义引用类型 其中d是声明的变量名 一 一般引用 一般在初始化变量时
  • 提高C++性能的编程技术笔记:多线程内存池+测试代码

    为了使多个线程并发地分配和释放内存 必须在分配器方法中添加互斥锁 全局内存管理器 通过new 和delete 实现 是通用的 因此它的开销也非常大 因为单线程内存管理器要比多线程内存管理器快的多 所以如果要分配的大多数内存块限于单线程中使用
  • Linux下遍历指定目录的C++实现

    之前在 https blog csdn net fengbingchun article details 51474728 给出了在Windows遍历指定文件夹的C 实现 这里给出在Linux下遍历目录的实现 Windows和Linux下的
  • 程序员的自我修养--链接、装载与库笔记:Linux共享库的组织

    共享库 Shared Library 概念 其实从文件结构上来讲 共享库和共享对象没什么区别 Linux下的共享库就是普通的ELF共享对象 由于共享对象可以被各个程序之间共享 所以它也就成为了库的很好的存在形式 很多库的开发者都以共享对象的
  • C++中插件使用举例

    插件并不是在构建时链接的 而是在运行时发现并加载的 因此 用户可以利用你定义好的插件API来编写自己的插件 这样他们就能以指定方式扩展API的功能 插件库是一个动态库 它可以独立于核心API编译 在运行时根据需要显示加载 不过插件也可以使用
  • C++中vector的使用

    向量std vector是一种对象实体 能够容纳许多各种类型相同的元素 包括用户自定义的类 因此又被称为序列容器 与string相同 vector同属于STL Standard Template Library 中的一种自定义的数据类型 可
  • C++中typeid的使用

    RTTI Run TimeType Information 运行时类型信息 它提供了运行时确定对象类型的方法 在C 中 为了支持RTTI提供了两个操作符 dynamic cast和typeid The typeid operator pro
  • CSV文件简介及C++实现

    逗号分隔值 Comma Separated Values CSV 有时也称为字符分隔值 因为分隔字符也可以不是逗号 其文件以纯文本形式存储表格数据 数字和文本 纯文本意味着该文件是一个字符序列 不含必须象二进制数字那样被解读的数据 CSV文
  • C/C++中#pragma once的使用

    在C C 中 为了避免同一个文件被include多次 有两种方式 一种是 ifndef方式 一种是 pragma once方式 在头文件的最开始加入 ifndef SOME UNIQUE NAME HERE define SOME UNIQ
  • C++11中thread_local的使用

    C 11中的thread local是C 存储期的一种 属于线程存储期 存储期定义C 程序中变量 函数的范围 可见性 和生命周期 C 程序中可用的存储期包括auto register static extern mutable和thread
  • C++11中std::shared_future的使用

    C 11中的std shared future是个模板类 与std future类似 std shared future提供了一种访问异步操作结果的机制 不同于std future std shared future允许多个线程等待同一个共
  • C++中std::sort/std::stable_sort/std::partial_sort的区别及使用

    某些算法会重排容器中元素的顺序 如std sort 调用sort会重排输入序列中的元素 使之有序 它默认是利用元素类型的 lt 运算符来实现排序的 也可以重载sort的默认排序 即通过sort的第三个参数 此参数是一个谓词 predicat
  • C++/C++11中变长参数的使用

    C C 11中的变长参数可以应用在宏 函数 模板中 1 宏 在C99标准中 程序员可以使用变长参数的宏定义 变长参数的宏定义是指在宏定义中参数列表的最后一个参数为省略号 而预定义宏 VA ARGS 则可以在宏定义的实现部分替换省略号所代表的

随机推荐

  • 通过liquibase将PostgreSQL数据库导入到H2数据库

    1 背景 项目中使用的数据库是PostgreSQL 在做测试时 想使用H2代替 2 问题 2 1 保留字 在PostgreSQL中使用了几个H2的保留字 例如 end offset foreign 这些保留字是不能作为表的字段名 2 2 字
  • Java加解密的基础

    在Java的安全包中 包括了三部分内容 1 JCA JCE Java Cryptography Architecture JavaCryptography Extensions 2 JSSE Java Secure Sockets Exte
  • Jenkins + NACOS + GATEWAY 实现微服务不停机部署

    Nacos 版本
  • 【第11篇】MobileNetV2:倒置残差和线性瓶颈

    MobileNetV2 倒置残差和线性瓶颈 文章目录 MobileNetV2 倒置残差和线性瓶颈 摘要 1 简介 2 相关工作 3 预备 讨论和直觉 3 1 深度可分离卷积 3 2 线性瓶颈 3 3 倒置残差 3 4 信息流解读 4 模型架
  • LCD和FSMC的那点事 和STM32F4 FSMC 34PIN 16位数据并口 TFTLCD,点亮屏幕步骤

    LCD和FSMC的那点事 A 先说一下几种LCD interface 包括但不限于以下三种 1 SPI 2 FSMC 就是常说的8080 或者称80并口 都是一个意思 参考 STM32 FSMC模拟8080时序 点亮 液晶屏 点亮显示屏的几
  • 复习向 C/C++ 编程语言简介和概括(C++复习向p1)

    文章目录 C 编程语言 C 和 C 关系 标准的 C 组成 ANSI 标准 比较重要的标准化时间 C 编程语言 是一种静态类型的 编译式的 通用式的 大小写敏感 不规则的编程语言 支持过程化编程 面向对象 泛型编程 C 和 C 关系 C 是
  • mybatis-plus Invalid bound statement (not found):

    1 若是使用了多数据源配置 请检查 DataSourceConfig配置类 将SqlSessionFactoryBean改为mybatis plus里面的MybatisSqlSessionFactoryBean Bean name test
  • 一键磨皮插件:DR5白金版(支持ps 2022)中文版

    Delicious Retouch 5简称DR5 这里为大家分享最新激活的DR5白金版 for mac 这是非常受欢迎的一款PS一键磨皮插件 dr5插件提供了人像磨皮 平滑皮肤 去除瑕疵 美白牙齿 美白皮肤 修饰眼部等功能 一键点击即可使用
  • win10+CPU+Anaconda3 环境下pytorch安装

    本文主要对win10环境下 仅CPU运行 Anaconda3中安装pytorch的步骤进行了记录 主要包括以下内容 1 conda 创建虚拟环境 2 conda 添加镜像源 3 pytorch 安装 4 pytorch 成功安装验证 con
  • Unity官网打不开,试试新地址吧!

    今年6月份发现unity官网进不去了 unity3d com unity com cn 下载历史版本的地址也打不开 网上也有很多人求助 新域名如下 不需要挂vpn 新地址 https unity cn 历史版本下载 https unity
  • Python多线程的理解和使用(一)Threading中join()函数的理解

    转载自 https blog csdn net zhuzuwei article details 80927554 多线程的概念 多线程类似于同时执行多个不同程序 多线程运行有如下优点 使用线程可以把占据长时间的程序中的任务放到后台去处理
  • python操作redis

    目录 python操作redis 安装redis模块 基本链接 连接池连接 redis字符串操作 redis hash操作 redis 列表操作 redis 其它操作 redis管道 django中集成redis python操作redis
  • 为本地项目配置git地址,并推送到远程仓库

    1 进入该项目文件夹 cd Users kk Desktop project k demo 将上面项目路径换成你自己的项目路径 2 初始化git 使用git init 将该项目变成一个可以通过git管理的项目 git init 3 通过gi
  • vue-cli使用指南

    目录 vue全家桶 技术栈 使用vue cli搭建Vue项目 单页的编写 axios的使用 vuex的使用 vuex中数据的保留时间 axios的全局拦截 axios的跨域问题 全局常量 使用Mock模拟后端接口返回数据 嵌套路由 路由守卫
  • 95-38-030-Buffer-Java NIO中-关于DirectBuffer,HeapBuffer的疑问

    文章目录 1 说明 2 疑问 3 RednaxelaFX 1 说明 本文摘要 https www zhihu com question 57374068 2 疑问 Java NIO中 关于DirectBuffer HeapBuffer的疑问
  • CUDA的几种Synchronize

    首先对这三个函数做一下解释 cudaDeviceSynchronize 等待所有线程都处理完成 kernel function处理完成 用在cpu的c code中 cudaThreadSynchronize 功能和cudaDeviceSyn
  • Pycharm的使用技巧与效率提升

    总第010篇 本文主要梳理了pycharm在使用过程中的一些技巧 便于提升工作效率 pycharm主要分为两个版本 一个是专业版本 此版本功能强大 主要是为python和web开发者准备的 需要付费 另一个是社区版本 比较轻量级 主要是为p
  • 读别人写的代码 VS 自己写代码

    概述 专业程序员非常重要的一项技能是读别人写的代码 这项技能甚至比自己写代码更重要 分析 这让我想到很多程序员讨厌去阅读代码 来接受它吧 人人都喜欢编写代码 写代码是很有乐趣的事 但阅读代码却是一种困难的工作 它不仅仅繁重 而且很无聊 让我
  • 使用Docker进行模型部署

    文章目录 1 思路 2 实现步骤 2 1 数据 模型准备 2 2 镜像制作 2 3 使用 1 思路 因为多数公司正式集群都不能使用公网环境 对于模型部署比较麻烦 所以想这在公网环境下完成模型调试 然后根据相关环境和参数直接制作一个docke
  • C++中static_cast/const_cast/dynamic_cast/reinterpret_cast的区别和使用

    C风格的强制转换较简单 如将float a转换为int b 则可以这样 b int a 或者b int a C 类型转换分为隐式类型转换和显示类型转换 隐式类型转换又称为标准转换 包括以下几种情况 1 算术转换 在混合类型的算术表达式中 最