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

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.mfbz.cn/a/207572.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【前缀和]LeetCode1862:向下取整数对和

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个整数数组 nums &#xff0c;请你返回所有下标对 0 < i, j < nums.length 的 …

一文带你了解网络安全简史

网络安全简史 1. 上古时代1.1 计算机病毒的理论原型1.2 早期计算机病毒1.3 主要特点 2. 黑客时代2.1 计算机病毒的大流行2.2 知名计算机病毒2.3 主要特点 3. 黑产时代3.1 网络威胁持续升级3.2 代表性事件3.3 主要特点 4 高级威胁时代4.1 高级威胁时代到来4.2 著名的APT组织4.3 …

Python之Requests模块简介与安装

Requests模块简介 在python的标准库中&#xff0c;虽然提供了urllib,utllib2,httplib&#xff0c;但是做接口测试&#xff0c;requests使用更加方便快捷&#xff0c;正如官方说的&#xff0c;“让HTTP服务人类”。 Requests是用python语言基于urllib编写的&#xff0c;采用的是…

利用异或、取反、自增bypass_webshell_waf

目录 引言 利用异或 介绍 eval与assert 蚁剑连接 进阶题目 利用取反 利用自增 引言 有这样一个waf用于防御我们上传的文件&#xff1a; function fun($var): bool{$blacklist ["\$_", "eval","copy" ,"assert","usort…

折扣因子的变化图(Python)

var 3 var_list [3] for _ in range(50):var * .95var_list.append(var)import matplotlib.pyplot as plt import numpy as np plt.plot(np.arange(len(var_list)), var_list, linewidth1) plt.show()

美丽的时钟

案例绘制一个时钟 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>美丽的时钟</title><script language"javascript">window.onloadfunction(){var clockdocument.getElementById("clock"…

你需要知道所有设计模式吗?

后续我会详细展开设计模式 &#x1d5d7;&#x1d5fc; &#x1d5ec;&#x1d5fc;&#x1d602; &#x1d5e1;&#x1d5f2;&#x1d5f2;&#x1d5f1; &#x1d5e7;&#x1d5fc; &#x1d5de;&#x1d5fb;&#x1d5fc;&#x1d604; &#x1d5d4;&#x1d5f9;&…

溜冰场电脑收银系统软件会员管理操作教程,佳易王溜冰场会员卡管理软件下载

溜冰场电脑收银系统软件会员管理操作教程&#xff0c;佳易王溜冰场会员卡管理软件下载 一、软件 部分功能简介&#xff1a; 1、会员信息登记 &#xff1a;可以直接使用手机号登记&#xff0c;也可以使用实体卡片&#xff0c;推荐用手机号即可。 2、会员卡类型 &#xff1a;可…

Redis:事务操作

目录 Redis事务定义相关命令事务的错误处事务冲突的问题Redis事务三特性 Redis事务定义 redis事务是一个单独的隔离操作&#xff0c;事务中的所有命令都会序列化、按顺序地执行&#xff0c;事务在执行的过程中&#xff0c;不会被其他客户端发送来的命令请求所打断。 redis事务…

HTAP 还可以这么玩?丨TiDB 在 IoT 智慧园区的应用

作者&#xff1a;某物联网公司设施云平台负责人 用户简介&#xff1a;我们是一家提供全链智慧园区整体解决方案的物联网公司&#xff0c;致力于打造可持续发展的智慧园区。 基础设施平台简介 基础设施平台是集团一线作业人员日常工作中高度依赖的重要系统&#xff0c;涵盖了各…

涉密计算机违规外联原因及防范措施

高度信息化的时代&#xff0c;涉密计算机违规外联已成为一种严重的安全威胁。涉密计算机违规外联是指涉密计算机通过互联网、电子邮件等方式与外部计算机或网络进行连接&#xff0c;导致机密信息泄露或被恶意攻击。 为了应对这一问题&#xff0c;本文将探讨涉密计算机违规外联的…

WPF实战项目十九(客户端):修改RestSharp的引用

修改HttpRestClient&#xff0c;更新RestSharp到110.2.0&#xff0c;因为106版本和110版本的代码不一样&#xff0c;所以需要修改下代码 using Newtonsoft.Json; using RestSharp; using System; using System.Threading.Tasks; using WPFProjectShared;namespace WPFProject.S…

wps备份功能 救了我一命

感谢wps备份功能 救了我一命 文章目录 感谢wps备份功能 救了我一命**&#x1f4dd;场景回现&#xff0c;往后再不干了**&#x1f9e3;灵光一现&#x1f4c7;备注中心的设置流程&#x1f58a;️最后总结 &#x1f4dd;场景回现&#xff0c;往后再不干了 小&#x1f42e;今天接到…

理解BatchNormalization层的作用

深度学习 文章目录 深度学习前言一、“Internal Covariate Shift”问题二、BatchNorm的本质思想三、训练阶段如何做BatchNorm四、BatchNorm的推理(Inference)过程五、BatchNorm的好处六、机器学习中mini-batch和batch有什么区别 前言 Batch Normalization作为最近一年来DL的重…

Spring Task

1 介绍 Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 定位&#xff1a;定时任务框架 作用&#xff1a;定时自动执行某段Java代码 为什么要在Java程序中使用Spring Task&#xff1f; 应用场景&#xff1a; 1). 信用卡…

MyBatis-Plus动态表名使用selectPage方法不生效问题解析与解决

文章目录 MyBatis-Plus动态表名简介selectPage方法不生效的问题解决方案&#xff1a;SqlParser注解与BaseMapper的selectPage方法示例代码实体类Mapper接口Service层Controller层 总结 &#x1f389;MyBatis-Plus动态表名使用selectPage方法不生效问题解析与解决 ☆* o(≧▽≦)…

【每日OJ —— 144. 二叉树的前序遍历】

每日OJ —— 144. 二叉树的前序遍历 1.题目&#xff1a;144. 二叉树的前序遍历2.方法讲解2.1.算法讲解2.2.代码实现2.3.提交通过展示 1.题目&#xff1a;144. 二叉树的前序遍历 2.方法讲解 2.1.算法讲解 1.首先如果在每次每个节点遍历的时候都去为数组开辟空间&#xff0c;这样…

linux基础五:linux 系统(进程状态2:)

linux 系统 一.进程状态&#xff1a;1.睡眠状态(sleep)&#xff1a;2.磁盘休眠状态(disk sleep)&#xff1a;3.停止状态(stoped --- T)&#xff1a;4.死亡状态&#xff1a;5.控制状态&#xff08;t&#xff09; 二.僵尸进程和孤儿进程&#xff1a;1.僵尸状态&#xff1a;2.孤儿…

同城服务足浴按摩软件系统开发方案;

足浴按摩软件是一款线上系统小程序&#xff0c;旨在方便用户在线预约按摩师、选择适合自己的服务项目和时间&#xff0c;并在家中或指定地点享受按摩服务。这款上门按摩小程序为用户提供了便利和个性化的按摩服务体验。 用户可以通过手机随时随地通过足浴按摩软件预约按摩师&am…

【java】编译时bug 项目启动前bug合集

文章目录 1. jdk8中 Optional orElseThrow 编译时报错java: 未报告的异常错误X; 必须对其进行捕获或声明以便抛出2. 启动项目时提示 Error running Application: Command line is too long. Shorten command line for Application or also for Spring Boot default configurati…
最新文章