C++相关闲碎记录(2)

news2024/9/20 17:41:45

1、误用shared_ptr

int* p = new int;
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(p);  //error 
// 通过原始指针两次创建shared_ptr是错误的

shared_ptr<int> sp1(new int);
shared_ptr<int> sp2(sp1);  //ok

如果对C++相关闲碎记录(1)中记录的shared_ptr的使用例子修改为如下:父类添加孩子的shared_ptr时调用下面这个函数来实现,同样会出现问题:

class Person {
public:
    string name;
    shared_ptr<Person> mother;
    shared_ptr<Person> father;
    vector<weak_ptr<Person>> kids;   //使用weak_ptr

    Person(const string& n, shared_ptr<Person> m = nullptr,
           shared_ptr<Person> f = nullptr) :name(n), mother(m), father(f) {}
        
    ~Person() {
        cout << "delete " << name << endl;
    }

    void setParentAndTheirKids(shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr) {
        mother = m;
        father = f;
        if (m != nullptr) {
            m->kids.push_back(shared_ptr<Person>(this));  //error
            // 为什么这里会报错,因为this所指的对象已经有一个shared_ptr了,再通过这种方式创建shared_ptr就会报错,因为会重新开启一个拥有者团队
        }
        if (f != nullptr){
            f->kids.push_back(shared_ptr<Person>(this)); //error
        }
    }
};

shared_ptr<Person> initFamily(const string& name) {
    shared_ptr<Person> mom(new Person(name + "'s mom"));
    shared_ptr<Person> dad(new Person(name + "'s dad"));
    shared_ptr<Person> kid(new Person(name));
    kid->setParentAndTheirKids(mom, dad);
    return kid;
}

使用enable_shared_from_this<Person>

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

class Person : public enable_shared_from_this<Person> {
  public:
    string name;
    shared_ptr<Person> mother;
    shared_ptr<Person> father;
    vector<weak_ptr<Person>> kids;  // weak pointer !!!

    Person (const string& n)
     : name(n) {
    }

    void setParentsAndTheirKids (shared_ptr<Person> m = nullptr,
                                 shared_ptr<Person> f = nullptr) {
        mother = m;
        father = f;
        if (m != nullptr) {
            m->kids.push_back(shared_from_this());
        }
        if (f != nullptr) {
            f->kids.push_back(shared_from_this());
        }
    }

    ~Person() {
      cout << "delete " << name << endl;
    }
};

shared_ptr<Person> initFamily (const string& name)
{
    shared_ptr<Person> mom(new Person(name+"'s mom")); 
    shared_ptr<Person> dad(new Person(name+"'s dad")); 
    shared_ptr<Person> kid(new Person(name)); 
    kid->setParentsAndTheirKids(mom,dad); 
    return kid;
}

int main()
{
    shared_ptr<Person> p = initFamily("nico");
    cout << "nico's family exists" << endl;
    cout << "- nico is shared " << p.use_count() << " times" << endl;
    cout << "- name of 1st kid of nico's mom: " 
         << p->mother->kids[0].lock()->name << endl;

    p = initFamily("jim");
    cout << "jim's family exists" << endl;
}

shared_ptr各种操作:

 

shared_ptr<void> sp(new int);
shared_ptr<int>(static_cast<int*>(sp.get()))   //error
static_pointer_cast<int*>(sp)

std::unique_ptr<int> up = new int;  //error
std::unique_ptr<int> up(new int); // ok

unique_ptr不必一定拥有对象,也可以是empty。

std::unique_ptr<std::string> up;
可以赋值为nullptr或者调用reset
up = nullptr;
up.reset();

unique_ptr可以调用release(),释放所拥有的对象,并将所有权交给调用者。

std::unique_ptr<std::string> up(new std::string("nico"));
std::string* sp = up.release();

2、转移unique_ptr的拥有权

std::string* sp = new std::string("hello");
std::unique_ptr<std::string> up1(sp);
std::unique_ptr<std::string) up2(sp);  //error  up1 and up2 own same data

std::unique_ptr<std::string[]> up(new std::string[10]);  //ok
此偏特化不再提供操作符*和->,而提供[]操作符,访问array中的一个对象时,使用[]

std::cout << *up << std::endl; //error
std::cout << up[0] << std::endl;  //ok

指定自定义删除器:通过类的方式指定

class ClassADeleter {
public:
    void operator() (ClassA* p) {
        std::cout << "call delete for ClassA object" << std::endl;
        delete p;
    }
};

std::unique_ptr<ClassA, ClassADeleter> up(new ClassA());

如果是个函数或者lambda,必须声明deleter的类型为void(*)(T*)或者std::function<void(T*)>,要不就使用decltype,例如要为array of int指定自己的deleter,并以lambda形式呈现:

std::unique_ptr<int, void(*)(int*)> up(new int[10], 
                                        [](int* p) {
                                            delete []p;});


std::unique_ptr<int, std::function<void(int*)>> up(new int[10], 
                                        [](int* p) {
                                            delete []p;});

或者
auto l = [](int*) {delete [] p;};
std::unique_ptr<int, decltype(l)>> up(new int[10], l);

 为了避免传递function pointer 或者lambda 时必须指明deleter的类型,你可以使用alias template

template<typename T>
using uniquePtr = std::unique_ptr<T, void(*)(T*)>;

uniquePtr<int> up(new int[10], [](int* p) {delete [] p;});

unique_ptr各种操作:

 3、numeric_limits<>

#include <iostream>
#include <limits>
#include <string>
using namespace std;

int main()
{
   // use textual representation for bool
   cout << boolalpha;

   // print maximum of integral types
   cout << "max(short): " << numeric_limits<short>::max() << endl;
   cout << "max(int):   " << numeric_limits<int>::max() << endl;
   cout << "max(long):  " << numeric_limits<long>::max() << endl;
   cout << endl;

   // print maximum of floating-point types
   cout << "max(float):       "
        << numeric_limits<float>::max() << endl;
   cout << "max(double):      "
        << numeric_limits<double>::max() << endl;
   cout << "max(long double): "
        << numeric_limits<long double>::max() << endl;
   cout << endl;

   // print whether char is signed
   cout << "is_signed(char): "
        << numeric_limits<char>::is_signed << endl;
   cout << endl;

   // print whether numeric limits for type string exist
   cout << "is_specialized(string): "
        << numeric_limits<string>::is_specialized << endl;
}

 4、type trait的使用

#include <iostream>
#include <limits>
#include <string>
using namespace std;

// type trait
template <typename T>
void foo_impl(T val, true_type) {
    std::cout << "Integer" << std::endl;
}

template <typename T>
void foo_impl(T val, false_type) {
    std::cout << "not Integer" << std::endl;
}

template <typename T>
void foo(T val) {
    foo_impl(val, std::is_integral<T>());
}

int main()
{
    double d_a = 1.2;
    long long int ll_b = 33333;
    foo(d_a);
    foo(ll_b);
}

输出:
not Integer
Integer
类型判断工具

 用以阐明class细节的trait
#include <iostream>
#include <limits>
#include <type_traits>
using namespace std;


int main()
{
    std::cout << boolalpha << is_const<int>::value << endl;                    //false
    std::cout << boolalpha << is_const<const volatile int>::value << endl;     //true
    std::cout << boolalpha << is_const<int* const>::value << endl;             //true
    std::cout << boolalpha << is_const<const int*>::value << endl;             //false
    std::cout << boolalpha << is_const<const int&>::value << endl;             //false
    std::cout << boolalpha << is_const<int[3]>::value << endl;                 //false
    std::cout << boolalpha << is_const<const int[3]>::value << endl;           //true
    std::cout << boolalpha << is_const<int[]>::value << endl;                  //false
    std::cout << boolalpha << is_const<const int[]>::value << endl;            //true

    return 0;
}

 指向const类型的非常量指针或者引用,并不是一个常量,尽管内含元素是常量,例如const int* 并不是常量,只是描述指针所指向的这个变量是常量类型,但是指针本身可以重新指向新的变量。

用以检测copy和move语义的那些个trait,只检测是否相应的表达式为可能,例如一个带有copy构造函数的(接受常量实参)但没有move构造函数的类型,仍然是move constructible.

用以检验类型关系的trait 

 

int main()
{
    std::cout << boolalpha << is_assignable<int, int>::value << endl;                               //false
    std::cout << boolalpha << is_assignable<int&, int>::value << endl;                              //true
    std::cout << boolalpha << is_assignable<int&&, int>::value << endl;                             //false
    std::cout << boolalpha << is_assignable<long&, int>::value << endl;                             //true
    std::cout << boolalpha << is_assignable<int&, void*>::value << endl;                            //false
    std::cout << boolalpha << is_assignable<void*, int>::value << endl;                             //false
    std::cout << boolalpha << is_assignable<const char*, std::string>::value << endl;               //false
    std::cout << boolalpha << is_assignable<std::string, const char*>::value << endl;               //true
    
    std::cout << boolalpha << is_constructible<int>::value << endl;                                 //true
    std::cout << boolalpha << is_constructible<int, int>::value << endl;                            //true
    std::cout << boolalpha << is_constructible<long, int>::value << endl;                           //true
    std::cout << boolalpha << is_constructible<int, void*>::value << endl;                          //false
    std::cout << boolalpha << is_constructible<void*, int>::value << endl;                          //false
    std::cout << boolalpha << is_constructible<const char*, std::string>::value << endl;            //false
    std::cout << boolalpha << is_constructible<std::string, const char*>::value << endl;            //true
    std::cout << boolalpha << is_constructible<std::string, const char*, int, int>::value << endl;  //true

    return 0;
}

5、类型修饰符

#include <iostream>
#include <limits>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;


int main()
{
    typedef int T;
    typedef add_const<T>::type A;                //const int
    typedef add_lvalue_reference<T>::type B;     //int&
    typedef add_rvalue_reference<T>::type C;     //int&&
    typedef add_pointer<T>::type D;              //int*
    typedef make_signed<T>::type E;              //int
    typedef make_unsigned<T>::type F;            //unsigned int
    typedef remove_const<T>::type G;             //int
    typedef remove_reference<T>::type H;         //int
    typedef remove_pointer<T>::type I;           //int

    std::cout << boolalpha << is_const<A>::value << std::endl;

    // 查看完整类型
    std::cout << abi::__cxa_demangle(typeid(A).name(),0,0,0 ) << std::endl;
    std::cout << typeid(B).name() << std::endl;

    std::cout << "A is same const int ?" << boolalpha << is_same<const int, A>::value << std::endl;
    std::cout << "B is same int& ?" << boolalpha << is_same<int&, B>::value << std::endl;

    typedef const int& T1;
    typedef add_const<T1>::type A1;                  // const int&
    typedef add_lvalue_reference<T1>::type B1;       //const int&
    typedef add_rvalue_reference<T1>::type C1;       //const int& (yes, lvalue remains lvalue)
    typedef add_pointer<T1>::type D1;                //const int*
    // typedef make_signed<T1>::type E1;             //undefined behavior
    // typedef make_unsigned<T1>::type F1;           //undefined bahavior
    typedef remove_const<T1>::type G1;               //const int&
    typedef remove_reference<T1>::type H1;           //const int
    typedef remove_pointer<T1>::type I1;             //cosnt int&

    std::cout << "A1 is same const int& ?" << boolalpha << is_same<const int&, A1>::value << std::endl;
    std::cout << is_const<A1>::value << std::endl;
    std::cout << "G1 is same const int& ?" << boolalpha << is_same<const int&, G1>::value << std::endl;

    return 0;
}

 指向某常量类型的reference本身并不是常量,所以不可以移除const,add_pointer<>必然包含使用remove_reference<>,然而make_signed<>和make_unsigned<>必须是整型,枚举型,bool除外,所以传入引用会导致不明确的行为。add_lvalue_reference<>把一个rvalue reference转换为一个lvalue reference,然而add_rvalue_reference<>并不会把一个lvalue reference转换为一个rvalue reference.

6、其他type trait 

#include <iostream>
#include <limits>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;


int main()
{
    std::cout << rank<int>::value << std::endl;                   //0
    std::cout << rank<int[]>::value << std::endl;                 //1
    std::cout << rank<int[3]>::value << std::endl;                //1
    std::cout << rank<int[][4]>::value << std::endl;              //2
    std::cout << rank<int[3][4]>::value << std::endl;             //2

    std::cout << extent<int>::value << std::endl;                 //0
    std::cout << extent<int[]>::value << std::endl;               //0
    std::cout << extent<int[3]>::value << std::endl;              //3
    std::cout << extent<int[][4]>::value << std::endl;            //0
    std::cout << extent<int[3][3]>::value << std::endl;           //3
    std::cout << extent<int[][3], 1>::value << std::endl;         //3
    std::cout << extent<int[5][6], 1>::value << std::endl;        //6
    std::cout << extent<int[3][4], 2>::value << std::endl;        //0
   
    typedef remove_extent<int>::type A;                           //int
    typedef remove_extent<int[]>::type B;                         //int
    typedef remove_extent<int[3]>::type C;                        //int
    typedef remove_extent<int[][8]>::type D;                      //int[8]
    typedef remove_extent<int[5][6]>::type E;                     //int[7]
    typedef remove_all_extents<int>::type F;                      //int
    typedef remove_all_extents<int>::type G;                      //int
    typedef remove_all_extents<int[]>::type H;                    //int
    typedef remove_all_extents<int[5]>::type I;                   //int
    typedef remove_all_extents<int[][9]>::type J;                 //int
    typedef remove_all_extents<int[5][8]>::type K;                //int
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1273697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI - Steering behaviorsII(碰撞避免,跟随)

Steering Behaviors系统中的碰撞避免&#xff0c;路径跟随&#xff0c;队长跟随 Collision Avoid 在物体前进的方向&#xff0c;延伸一定长度的向量进行检测。相当于物体对前方一定可使范围进行检测障碍物的碰撞 延伸的向量与碰撞物圆心的距离小于碰撞物的半径&#xff0c;则…

docker-compose脚本编写及常用命令

安装 linux DOCKER_CONFIG/usr/local/lib/docker/cli-plugins sudo mkdir -p $DOCKER_CONFIG/cli-plugins sudo curl -SL https://521github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose sudo c…

numpy知识库:深入理解numpy.resize函数和数组的resize方法

前言 numpy中的resize函数顾名思义&#xff0c;可以用于调整数组的大小。但具体如何调整&#xff1f;数组形状变了&#xff0c;意味着数组中的元素个数发生了变化(增加或减少)&#xff0c;如何确定resize后的新数组中每个元素的数值呢&#xff1f;本次博文就来探讨并试图回答这…

润申信息企业标准化管理系统 SQL注入漏洞复现

0x01 产品简介 润申信息科技企业标准化管理系统通过给客户提供各种灵活的标准法规信息化管理解决方案&#xff0c;帮助他们实现了高效的标准法规管理&#xff0c;完成个性化标准法规库的信息化建设。 0x02 漏洞概述 润申信息科技企业标准化管理系统 CommentStandardHandler.as…

蓝桥杯每日一题2023.11.30

题目描述 九数组分数 - 蓝桥云课 (lanqiao.cn) 题目分析 此题目实际上是使用dfs进行数字确定&#xff0c;每次循环中将当前数字与剩下的数字进行交换 eg.1与2、3、4、、、进行交换 2与3、4、、、进行交换 填空位置将其恢复原来位置即可&#xff0c;也就直接将其交换回去即可…

鸿蒙原生应用/元服务开发-开发者如何进行真机测试

前提条件&#xff1a;已经完成鸿蒙原生应用/元服务开发&#xff0c;已经能相对熟练使用DevEco Studio,开发者自己有鸿蒙4.0及以上的真机设备。 真机测试具体流程如下 1.手机打开开发者模式 2.在项目中&#xff0c;左上角 文件(F)->项目结构 进行账号连接 3.运行

AS 之 gradle 命令

文章目录 1、命令大全2、编译命令2.1 检查依赖并编译打包2.2 编译并打 Debug 包2.3 编译打出 Debug 包并安装2.4 编译并打出 Release 包2.5 编译打出 Release 包并安装2.6 Debug/Release 编译并打印日志 3、清除命令4、卸载命令4.1 卸载 Debug/Release 安装包4.2 adb 卸载 5、调…

智能优化算法应用:基于风驱动算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于风驱动算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于风驱动算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.风驱动算法4.实验参数设定5.算法结果6.参考文献7.…

麒麟操作系统进入单用户模式

Kylin V4 桌面版&#xff1a; 启动系统后&#xff0c;在启动菜单界面选择 Kylin 4.0.2 高级选项后回车。 在高级模式选项下选择第二行 recovery mode 模式后&#xff0c;按 e 编辑。 按 e 后如下图&#xff0c;找到 linux 开头的一行&#xff0c;修改 ro 为 rw 后&#xff0c…

将项目放到gitee上

参考 将IDEA中的项目上传到Gitee仓库中_哔哩哔哩_bilibili 如果cmd运行ssh不行的话&#xff0c;要换成git bash 如果初始化后的命令用不了&#xff0c;直接用idea项放右键&#xff0c;用git工具操作

[原创][3]探究C#多线程开发细节-“用ConcurrentQueue<T>解决多线程的无顺序性的问题“

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XXQQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi…

数据中心布线解决方案比较: DAC 电缆和 AOC 光缆

在当今的数字时代&#xff0c;数据中心是无数行业的支柱&#xff0c;它确保了信息的交换并维护关键数据的完整性。为了保持这些数据中心高效运行&#xff0c;选择正确的布线解决方案至关重要。在这方面&#xff0c;两种流行的选择是直连铜缆 (DAC) 和有源光缆 (AOC)。在本文中&…

论文绘图——局部细节放大

文章目录 前言一、绘图1.0版二、绘图2.0版三、总结 前言 我们经常在论文中会看到下面这些样式的图片&#xff1a;在图片中使用矩形框框出感兴趣的区域&#xff0c;然后在底部或者其他位置附上对应的局部放大的细节图&#xff0c;简洁好看。✨ 曾尝试使用过PPT制作&#xff0c;也…

用于缓存一些固定名称的小组件

项目中&#xff0c;用于缓存姓名、地名、单位名称等一些较固定名称的id-name小组件。用于减少一些表的关连操作和冗余字段。优化代码结构。扩展也方便&#xff0c;写不同的枚举就行了。 具体用法&#xff1a; {NameCacheUser.USER.getName(userId);NameCacheUser.ACCOUNT.getN…

GAN:WGAN前作

WGAN前作&#xff1a;有原则的方法来训练GANs 论文&#xff1a;https://arxiv.org/abs/1701.04862 发表&#xff1a;ICLR 2017 本文是wgan三部曲的第一部。文中并没有引入新的算法&#xff0c;而是标是朝着完全理解生成对抗网络的训练动态过程迈进理论性的一步。 文中基本是…

Django 模板引擎 (四)

一、Django模板引擎 一个强大的工具&#xff0c;用于在HTML页面中嵌入动态内容。它使用一种被称为Django模板语言&#xff08;Django Template Language&#xff09;的简单而强大的语法来处理模板。该模板语言使用”{% %}”进行标记&#xff0c;用于执行各种操作。 二、Django…

高效率:使用DBeaver连接spark-sql

提高运行效率一般采取底层使用spark引擎替换成hive引擎的方式提高效率&#xff0c;但替换引擎配置较为复杂考虑到兼容版本且容易出错&#xff0c;所以本篇将介绍使用DBeaver直接连接spark-sql快速操作hive数据库。 在spark目录下运行以下命令&#xff0c;创建一个SparkThirdSe…

TA、TB、TC油封各自用途

在机械系统应用中&#xff0c;油封在防止润滑剂从机器和轴承间隙泄漏方面发挥着至关重要的作用。在各种类型的油封中&#xff0c;常用的是TA、TB、TC密封件。本文将深入探讨这三种密封件各自的用途。 TA、TB和TC密封件都是油封的类型&#xff0c;但它们的设计和应用有所不同。…

java设计模式学习之【对象池模式】

文章目录 引言对象池模式简介定义与用途实现方式 使用场景优势与劣势对象池模式在Spring中的应用JDBC对象池示例代码地址小结 引言 对象池模式在资源管理和性能优化方面发挥着重要作用。这种模式通过重复使用已经初始化的对象&#xff0c;而不是频繁创建和销毁&#xff0c;减少…

计算机体系结构----流水线技术(三)

本文仅供学习&#xff0c;不作任何商业用途&#xff0c;严禁转载。绝大部分资料来自----计算机系统结构教程(第二版)张晨曦等 计算机体系结构----流水线技术&#xff08;三&#xff09; 3.1 流水线的基本概念3.1.1 什么是流水线3.1.2 流水线的分类1. 部件级流水线、处理机级流…