精华内容
下载资源
问答
  • C++野指针及c++指针使用注意点

    千次阅读 多人点赞 2019-08-29 16:11:33
    野指针及c++指针使用注意点 避免野指针的产生 “野指针”的成因主要有: 1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时...

    内容转自(部分已被本人编辑):https://www.cnblogs.com/mrlsx/p/5419030.html

    野指针及c++指针使用注意点

    避免野指针的产生

    “野指针”的成因主要有:

    1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。

    char *p; //此时p为野指针
    

    2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针.

    char *p=new char[10];  //指向堆中分配的内存首地址,p存储在栈区
    cin>> p;
    delete []p; //p重新变为野指针
    

    3)指针操作超越了变量的作用范围。          

    char *p=new char[10]; //指向堆中分配的内存首地址
    cin>> p;
    cout<<*(p+10); //可能输出未知数据
    

    指针的注意点:

    a.指针指向常量存储区对象

    char *p="abc";

    此时p指向的是一个字符串常量,不能对*p的内容进行写操作,如srtcpy(p,s)是错误的,因为p的内容为“abc”字符串常量,该数据存储在常量存储区,但可以对指针p进行操作,让其指向其他的内存空间。

    b.资源泄漏

    问题:

    1 #include<iostream>
    2 using namespace std;
    3 void main()
    4 {
    5     char *p=new char[3];  //分配三个字符空间,p指向该内存空间
    6     p="ab";             //此时改变p的指向,p指向了常量“ab”,而不再是new char分配的内存空间了,new char[3]开辟的三个字符空间没有被释放,从而造成了资源泄漏。
    7     delete []p;         //释放时报错,此时p指向的是字符串常量
    8 }

    结果:卡死

     

    改进:

    1 #include<iostream>
    2 using namespace std;
    3 void main()
    4 {
    5     char *p=new char[3];  //分配三个字符空间,p指向该内存空间
    6     strcpy(p,"ab");      //将"ab"存储到p指向的内存空间,而不是改变p的指向
    7     delete []p;         //ok
    8 }

    结果:正确

     

    c.内存越界

    1 char *p=new char[3];  //分配三个字符空间,p指向该内存空间
    2 strcpy(p,"abcd");    //将abcd存处在分配的内存空间中,由于strlen("abcd")=4>3,越界
    3 delete []p;         //ok
    

    d.返回值是指针

    问题:数组p[]中的内容为“hello world”,存储在栈区,函数结束时内容被清除,p变为野指针,可能导致乱码

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     char p[]="abc";
     6     return p;
     7 }
     8 void main()
     9 {
    10     cout<<f()<<endl;
    11 }

    结果:

     改进:

    1.加static限定,延长数组生存期

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     static char p[]="abc";  //此时数组为静态数组,存储在全局/静态区,生存期到程序结束,因此函数结束时不会销毁p
     6     return p;
     7 }
     8 void main()
     9 {
    10     cout<<f()<<endl;
    11 }

    结果:

     

    2.定义成指针型数组

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     char *p="abc";    //"abc"存储在文字常量区,p是指向常量的指针,生存期到程序结束
     6     return p;
     7 }
     8 void main()
     9 {
    10     cout<<f()<<endl;
    11 }

    结果:

     

    3.动态分配存储空间,存储在堆区

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     char *p=new char[5];  //动态分配存储空间,p指向堆区
     6     strcpy(p,"abc");   // 这里不能用p="abc",前面已经说明
     7     return p;
     8 }
     9 void main()
    10 {
    11     cout<<f()<<endl;
    12 }

    结果:

     e.指针做形参

    即所谓的地址传递,我们都知道地址传递的方式,形参的改变会导致实参的改变,但要注意的是,这里的改变是指指针所指内容的改变,而不是指针值的改变。因此,当形参改变会导致实参改变时,指针所指的内容是非const类型的,否则会出错。

    1.改变指针内容:

    void swap(int *a,int *b)   //交换的是*a,*b,即指针的内容,而不是指针a,b
    {
       int t;
       t=*a;
       *a=*b;
       *b=t;
    }

    2.改变指针值:

    #include<iostream>
    using namespace std;
    void fun(char *p)
    {
        p="cba";    //“cba”存放在文字常量区,让p指向常量"abc",这里改变的是指针值,实参并不会改变
    }
    void main()
    {
        char *p="abc";  //“abc”存放在文字常量区,p指向常量"abc"
        fun(p);
        cout<<p<<endl;   //输出"abc",而不是"cba"
    }

    结果:

    如果对于这里不容易理解:笔者作如下解释:

    改写代码:(注意看注释)

    #include<iostream>
    using namespace std;
    void fun(char *a)  //给形参换个名字
    {
        cout<<a<<endl;   //abc
        a="cba";         //“cba”存放在文字常量区,让a指向常量"cba"
        cout<<a<<endl;   //cba
    
        //证明这里只改变了指针a的指向,即改变的是指针值a的值,先前是“abc”的地址,后来是“cba”的地址。实参并不会改变。
    }
    void main()
    {
        char *p="abc";  //“abc”存放在文字常量区,p指向常量"abc"
        fun(p);
        cout<<p<<endl;   //输出"abc",而不是"cba"
    
        p="cba";
    	cout<<p<<endl;  //输出“cba”    实参p发生改变
        这就证明:在fun函数中,只是改变了形参的值。
    }

    main函数和fun函数中的"abc"、"cba"都是存放在文字常量区,是具有各自的编号地址的。可以自己调试用printf("%p\n",p);打印出地址,可以看到两个不同的地址。

     

    继续看下面的情况,修改指针的内容:

    #include<iostream>
    using namespace std;
    void fun(char *p)
    {
        p[0]='c';    //改变p的内容,即修改p[0]
    }
    void main()
    {
        char *p="abc";  //p指向常量"abc"
        fun(p);
        cout<<p<<endl;   //error,p所指内容为常量,不能修改
    }

    结果:

    注:p="ab"和strcpy(p,"ab"),含义不一样,前者指针p指向常量“ab”存储区域的首地址,改变了p最开始指向的new申请的内存空间;而后者是将“ab”分配到new申请的内存空间中;

    展开全文
  • C语言指针使用中的常见错误

    千次阅读 2017-11-25 12:06:30
    指针的作用特别强,对许多问题是必须的。同时,偶尔错用指针,会带来意想不到的错误,甚至是灾难性的后果。  指针错误难以定位,因为指针本身并... (一)使用未初始化的指针(uninitialized pointer) int main(v

          指针的作用特别强,对许多问题是必须的。同时,偶尔错用指针,会带来意想不到的错误,甚至是灾难性的后果。

          指针错误难以定位,因为指针本身并没有问题。问题在于,通过错误指针操作时,程序对未知内存区进行读写操作。读操作时,最坏的情况是取得无用数据;而写操作时,可能冲掉其他代码或数据。

          (一)使用未初始化的指针(uninitialized pointer)

    int main(void)
    {
      int x, *p;
    
      x = 10;
      *p = x; //错误,指针未初始化
    
      return 0;
    }


          上述程序将值10写到未知的内存位置,因为从未向指针p赋值,p的内容不确定。


          (二)误解指针的用法,将值当做地址赋给指针

    #include <stdio.h>
    
    int main(void)
    {
      int x, *p;
    
      x = 10;
      p = x;    //错误,应该是p=&x,指针保存的是地址,而不是值
    
      printf("%d", *p);
    
      return 0;
    }

          (三)这种错误是对内存中数据存放位置的错误假定。比较指向不同对象的指针时,容易产生意外结果。例如:

    char s[80], y[80];
    char *p1, *p2;
    
    p1 = s;
    p2 = y;
    if(p1 < p2) . . .    //错误,不能确保数据处于内存的同样位置,也不能确保各种机器都用同样的格式保存数据

          类似的错误是想当然地以为同时定义的两个数组在内存区是顺序排列,从而简单地对指针增值,期望像使用两者组成的一个数组那样跨越数组边界。例如:

    int first[10], second[10];
    int *p, t;
    
    p = first;
    for(t=0; t<20; ++t)  *p++ = t;

          (四)
    /* 这段程序有错误 */
    #include <string.h>
    #include <stdio.h>
    
    int main(void)
    {
      char *p1;
      char s[80];
    
      p1 = s;
      do {
        gets(s);  /* read a string */
    
        /* print the decimal equivalent of each
           character */
        while(*p1) printf(" %d", *p1++);
    
      } while(strcmp(s, "done"));
    
      return 0;
    }

          上述程序通过p1打印出与s中诸字符关联的ASCII值。问题是只对p赋值(s的地址)一次。第一轮循环中,p1指向s中首字符。第二轮循环时,因为未再置成s的起点,p值从第一轮的结束点继续。此时,p可能指向另一个串,另一个变量,甚至程序的某一段。正确程序应该是:

    #include <string.h>
    #include <stdio.h> 
    
    int main(void)
    {
      char *p1;
      char s[80];
    
      do {
        p1 = s; /* reset p1 to beginning of s */
        gets(s);  /* read a string */
    
        /* print the decimal equivalent of each
           character */
        while(*p1) printf(" %d", *p1++);
    
      } while(strcmp(s, "done"));
    
      return 0;
    }
    


    展开全文
  • C++类成员函数指针使用介绍

    万次阅读 多人点赞 2019-09-21 16:07:49
    在之前写过的博客中有介绍过函数指针指针函数的区别和简单用法(文章在这里),当时的Demo非常简单,都是C语言的写法,但是当在C++中直接像C那样使用类成员函数指针时就会报错:reference to non-static member ...

    前言

    在之前写过的博客中有介绍过函数指针和指针函数的区别和简单用法(文章在这里),当时的Demo非常简单,都是C语言的写法,但是当在C++中直接像C那样使用类成员函数指针时就会报错:reference to non-static member function must be called
    所以如果是C++中的成员函数指针其使用方法是有区别的,这里针对不同的场景做个补充说明。

    类成员函数的指针(非静态)

    指向类成员函数的指针与普通函数指针的区别在于,前者需要匹配函数的参数类型和个数以及返回值类型,还要匹配该函数指针所属的类类型。

    这是因为非静态的成员函数必须被绑定到一个类的对象或者指针上,才能得到被调用对象的this指针,然后才能调用指针所指的成员函数(所有类的对象都有自己数据成员的拷贝,但是成员函数都是共用的,为了区分是谁调用了成员函数,就必须有this指针,this指针是隐式的添加到函数参数列表里去的)。

    所以,对于类成员函数的指针使用包含以下几个步骤:

    声明: 指向类的成员函数的指针需要在指针前面加上类的类型,格式为:

    typedef 返回值 (类名::*指针类型名)(参数列表);
    

    赋值: 需要用类的成员函数地址赋值,格式为:

    指针类型名  指针名 = &类名::成员函数名;
    

    注意:这里的这个&符号是比较重要的:不加&,编译器会认为是在这里调用成员函数,所以需要给出参数列表,否则会报错;加了&,才认为是要获取函数指针。这是C++专门做了区别对待。

    调用: 针对调用的对象是对象还是指针,分别用.*和->*进行调用,格式为:

    (类对象.*指针名)(参数列表);
    
    (类指针->*指针名)(参数列表);
    

    注意:这里的前面一对括号是很重要的,因为()的优先级高于成员操作符指针的优先级。

    直接来看一个示例吧:

    class Calculation
    {
    public:
        int add(int a,int b){ //非静态函数
            return  a + b;
        }
    };
    
    typedef int (Calculation::*FuncCal)(int,int);
    
    int main()
    {
        FuncCal funAdd = &Calculation::add;
        Calculation * calPtr = new Calculation;
        int ret = (calPtr->*funAdd)(1,2);  //通过指针调用
    
        Calculation cal;
        int ret2 = (cal.*funAdd)(3,4);  //通过对象调用
    
        cout << "ret = " << ret << endl;
        cout << "ret2 = " << ret2 << endl;
        return 0;
    }
    

    指向类的静态函数的指针

    类的静态成员函数和普通函数的函数指针的区别在于,他们是不依赖于具体对象的,所有实例化的对象都共享同一个静态成员,所以静态成员也没有this指针的概念。

    所以,指向类的静态成员的指针就是普通的指针。

    class Calculation
    {
    public:
        static int add(int a,int b){ //非静态函数
            return  a + b;
        }
    };
    
    typedef int (*FuncCal)(int,int);
    
    int main()
    {
        FuncCal funAdd = &Calculation::add;
        int ret = (*funAdd)(1,2);  //直接引用
        int ret2 = funAdd(3,4);  //直接引用
    
        cout << "ret = " << ret << endl;
        cout << "ret2 = " << ret2 << endl;
        return 0;
    }
    
    

    总结以上两种情况的区别:

    • 如果是类的静态成员函数,那么使用函数指针和普通函数指针没区别,使用方法一样
    • 如果是类的非静态成员函数,那么使用函数指针需要加一个类限制一下。

    使用函数指针,很多情况下是用在函数的参数中,在一些复杂的计算,如果需要重复调用,并且每次调用的函数不一样,那么这时候使用函数指针就很方便了,可以减少代码量。

    参考资料:
    https://blog.csdn.net/houzijushi/article/details/81503409
    https://www.cnblogs.com/lvchaoshun/p/7806248.html
    https://www.cnblogs.com/AnnieKim/archive/2011/12/04/2275589.html

    展开全文
  • UE4 智能指针使用介绍

    万次阅读 多人点赞 2021-05-25 10:16:04
    原创文章,转载请注明出处。 UE4也有一套智能指针库,整理了一下做个介绍。也请大家做补充。...使用注意事项1)TSharePtr2)类型转换二.TShareRef1.如何创建一个TShareRef2.TShareRef如何进行类型转换1)TS

    原创文章,转载请注明出处。

    UE4也有一套智能指针库,整理了一下做个介绍。也请大家做补充。

    文章里面的代码下载链接:智能指针测试代码

    一.TSharePtr

    1.如何创建一个TSharePtr

    /*
    	智能指针如何使用
    */		
    void MySharePtrTest();
    TSharedPtr<ClassBase> m_pSharePtrBase;	///h中声明的
    
    //智能指针如何使用
    void AMyActor::MySharePtrTest()
    {
    	m_pSharePtrBase = MakeShareable(new ClassBase());
    	
    	指针是否为空, 如果为空的话,会执行断言check,导致程序直接崩溃
    	if (m_pSharePtrBase.IsValid() || m_pSharePtrBase.Get())
    	{
    		//使用nBase
    		m_pSharePtrBase->nBase;
    	}
    }
    

    2.TSharePtr如何进行类型转换

    先定义两个类,代码如下

    class ClassBase
    {
    public:
    	int32 nBase;
    };
    
    class ClassTop : public ClassBase
    {
    public:
    	void MyFunc();
    };
    

    1)TSharePtr转TSharePtr

    StaticCastSharedPtr 介绍

    //SharePtr类型转换成其他的SharePtr
    void MySharePtrTestCastToAnotherSharePtr();
    
    //SharePtr类型转换成其他的SharePtr
    void AMyActor::MySharePtrTestCastToAnotherSharePtr()
    {
    	//基类对象指向了派生类的成员.多态案例在这也是一样的
    	TSharedPtr<ClassBase> ptrbase = MakeShareable(new ClassTop());
    	TSharedPtr<ClassTop> ptrcast = StaticCastSharedPtr<ClassTop>(ptrbase);
    	if (ptrcast.IsValid())
    	{
    		ptrcast->MyFunc();
    	}
    }
    

    2)Const TSharePtr转TSharePtr

    ConstCastSharedPtr 介绍

    //Const SharePtr转换成其他的SharePtr
    void MyConstSharePtrTestCastToAnotherSharePtr();
    
    //Const SharePtr转换成其他的SharePtr
    void AMyActor::MyConstSharePtrTestCastToAnotherSharePtr()
    {
    	//基类对象指向了派生类的成员.多态案例在这也是一样的
    	const TSharedPtr<ClassBase> ptrbase = MakeShareable(new ClassTop());
    
    	{
    		//错误写法, 不能通过ConstCastSharedPtr直接转成派生类.
    		//TSharedPtr<ClassTop> ptrcast = ConstCastSharedPtr<ClassTop>(ptrbase);
    	}
    	{
    		//正确写法1
    		//先通过ConstCastSharedPtr转成非const的基类
    		TSharedPtr<ClassBase> ptrcast = ConstCastSharedPtr<ClassBase>(ptrbase);
    		//再通过StaticCastSharedPtr转换
    		TSharedPtr<ClassTop> ptrcast2 = StaticCastSharedPtr<ClassTop>(ptrcast);
    		if (ptrcast2.IsValid())
    		{
    			ptrcast2->MyFunc();
    		}
    	}
    
    	{
    		//正确写法2
    		//直接通过StaticCastSharedPtr转换
    		TSharedPtr<ClassTop> ptrcast = StaticCastSharedPtr<ClassTop>(ptrbase);
    		if (ptrcast.IsValid())
    		{
    			ptrcast->MyFunc();
    		}
    	}
    }
    

    3)TSharePtr转TShareRef

    ToSharedRef介绍

    //SharePtr类型转换成ShareRef类型
    void MySharePtrToShareRef();
    
    //SharePtr类型转换成ShareRef类型
    void AMyActor::MySharePtrToShareRef()
    {
    	TSharedPtr<ClassBase> ptr = MakeShareable<ClassBase>(new ClassTop());
    	if (ptr.IsValid())
    	{
    		TSharedRef<ClassBase> ref = ptr.ToSharedRef();
    	}
    }
    

    3.使用注意事项

    1)TSharePtr

    1>智能指针可以在.h中定义, 并且可以=nullptr
    ShareRef不允许在.h中定义的, 并且一直有值,在二中介绍
    2>注意使用前要判断.IsValid()注意是. 不是箭头
    3>或者使用.Get进行判断
    如果都有值的话再去调用重载的操作符->去获取值, 比较安全。因为使用->的时候会先判断智能指针是否有效, 如果无效的话,直接会导致断言(check),随后程序崩溃。下面贴一下重载的->源码 4>和C++11的shareptr一样,内部都是基于引用计数的。所以你可以通过GetSharedReferenceCount()获取到当前的引用计数 ```cpp FORCEINLINE ObjectType* operator->() const { check( IsValid() ); //可以看到这里的check return Object; } ``` ### 2)类型转换 1>ConstCastSharedPtr注意事项
    下面是错误写法, 不能通过ConstCastSharedPtr直接转成派生类
    TSharedPtr<ClassTop> ptrcast = ConstCastSharedPtr<ClassTop>(ptrbase);
    
    2>通过TSharedPtr中的ToSharedRef()方法可以将TSharePtr转换为TShareRef

    二.TShareRef

    1.如何创建一个TShareRef

    //SharePtr如何使用
    void MyShareRefTest();
    
    //SharePtr如何使用
    void AMyActor::MyShareRefTest()
    {
    	//TSharedRef没有IsValid方法, 因为它一直是有效的
    	TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
    	ref->nBase;
    }
    

    2.TShareRef如何进行类型转换

    1)TShareRef转TShareRef

    StaticCastSharedRef 介绍

    //ShareRef类型转换成其他的ShareRef
    void AMyActor::MyShareRefTestCastToAnotherShareRef()
    {
    	//TSharedRef没有IsValid方法, 因为它一直是有效的
    	TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
    	TSharedRef<ClassTop> refCast = StaticCastSharedRef<ClassTop>(ref);
    	refCast->MyFunc();
    }
    

    2)Const TShareRef转TShareRef

    ConstCastSharedRef 介绍

    //Const ShareRef转换成其他的ShareRef
    void AMyActor::MyConstShareRefTestCastToAnotherShareRef()
    {
    	//TSharedRef没有IsValid方法, 因为它一直是有效的
    	const TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
    
    	{
    		//错误写法, 不能通过ConstCastSharedRef直接转成派生类.
    		//TSharedRef<ClassTop> refcast1 = ConstCastSharedRef<ClassTop>(ref);
    	}
    	{
    		//正确写法1, 先通过ConstCastSharedRef转换城非Const的基类
    		TSharedRef<ClassBase> refcast1 = ConstCastSharedRef<ClassBase>(ref);
    		//再通过StaticCastSharedRef转换
    		TSharedRef<ClassTop> refcast2 = StaticCastSharedRef<ClassTop>(refcast1);
    		refcast2->MyFunc();
    	}
    
    	{
    		//正确写法2
    		//直接通过StaticCastSharedRef转换
    		TSharedPtr<ClassTop> refcast = StaticCastSharedRef<ClassTop>(ref);
    		if (refcast.IsValid())
    		{
    			refcast->MyFunc();
    		}
    	}
    }
    

    3)TShareRef转TSharePtr

    直接赋值即可完成转换动作

    //ShareRef类型转换成SharePtr类型
    void MyShareRefToSharePtr();
    
    //ShareRef类型转换成SharePtr类型
    void AMyActor::MyShareRefToSharePtr()
    {
    	TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
    	TSharedPtr<ClassBase> ptr = ref;
    }
    

    3.使用注意事项

    1)TShareRef

    1>ShareRef不允许在.h中定义的, 我这弄了个为什么不允许在.h中的案例,会崩溃,截图

    在这里插入图片描述
    在这里插入图片描述

    2>不能=nullptr这么写

    3>使用时候直接用->即可,因为一直有有效值。

    2)类型转换

    1>ConstCastSharedRef注意事项
    下面是错误写法, 不能通过ConstCastSharedRef直接转成派生类
    TSharedRef<ClassTop> refcast1 = ConstCastSharedRef<ClassTop>(ref);
    
    2>将TSharedRef转换成TSharedPtr,直接赋值即可

    三.TWeakPtr

    TWeakPtr有两个奇妙之处
    1>他是保持对一个对象的弱引用,不会阻止对象(TWeakPtr)的销毁。如果TWeakPtr销毁了,那么这个弱指针(TWeakPtr)也会为null。也就是不需要我们二次维护了。
    2>打破TSharedPtr共享指针带来的循环引用问题

    1.如何创建一个TWeakPtr

    TWeakPtr的创建必须基于一个TSharedPtr或者TSharedRef

    1)通过TSharedPtr初始化一个TWeakPtr

    //TWeakPtr如何使用
    void MyWeakPtrTest();
    
    //TWeakPtr如何使用
    void AMyActor::MyWeakPtrTest()
    {
    	TSharedPtr<ClassBase> ptr = MakeShareable(new ClassTop());
    	//通过SharePtr初始化TWeakPtr
    	TWeakPtr<ClassBase> WeakPtr = ptr;
    	TWeakPtr<ClassBase> WeakPtr2(ptr);
    
    	//通过ShareRef初始化TWeakPtr
    	TSharedRef<ClassBase> ref = ptr.ToSharedRef();
    	TWeakPtr<ClassBase> WeakPtr3 = ref;
    	TWeakPtr<ClassBase> WeakPtr4(ref);
    }
    

    2)通过TSharedRef初始化一个TWeakPtr

    //通过ShareRef初始化TWeakPtr
    TSharedPtr<ClassBase> ptr = MakeShareable(new ClassTop());
    TSharedRef<ClassBase> ref = ptr.ToSharedRef();
    TWeakPtr<ClassBase> WeakPtr3 = ref;
    TWeakPtr<ClassBase> WeakPtr4(ref);
    

    2.TWeakPtr的类型转换

    TWeakPtr中的.Pin()函数可以将WeakPtr转成TSharedPtr

    1)TWeakPtr转TSharePtr

    //TWeakPtr如何转换成SharePtr
    void MyWeakPtrToSharePtr();
    
    //TWeakPtr如何转换成SharePtr
    void AMyActor::MyWeakPtrToSharePtr()
    {
    	TSharedPtr<ClassBase> ptr = MakeShareable(new ClassTop());
    	//通过SharePtr初始化TWeakPtr
    	TWeakPtr<ClassBase> WeakPtr = ptr;
    
    	//利用WeakPtr的.Pin()函数将WeakPtr转成SharedPtr
    	TSharedPtr<ClassBase> WeakPtrToSharePtrObj = WeakPtr.Pin();
    	if (WeakPtrToSharePtrObj.IsValid())
    	{
    		//tdo smth...
    	}
    }
    

    2)TWeakPtr转TShareRef

    其实就是先将WeakPtr转成SharedPtr,再将SharedPtr转SharedRef

    //TWeakPtr如何转换成ShareRef
    void MyWeakPtrToShareRef();
    
    
    //TWeakPtr如何转换成ShareRef
    void AMyActor::MyWeakPtrToShareRef()
    {
    	TSharedPtr<ClassBase> ptr = MakeShareable(new ClassTop());
    	//通过SharePtr初始化TWeakPtr
    	TWeakPtr<ClassBase> WeakPtr = ptr;
    
    	//利用WeakPtr的.Pin()函数将WeakPtr转成SharedPtr
    	TSharedPtr<ClassBase> WeakPtrToSharePtrObj = WeakPtr.Pin();
    	if (WeakPtrToSharePtrObj.IsValid())
    	{
    		//利用TSharedPtr的ToSharedRef()函数将TSharedPtr转换成TSharedRef
    		TSharedRef<ClassBase> ref = WeakPtrToSharePtrObj.ToSharedRef();
    	}
    }
    

    3.使用注意事项

    1>TWeakPtr一定是从TSharedPtr或者TSharedRef过来的

    四.TSharedFromThis

    将自己的F类继承自TSharedFromThis之后,那么这个类就会知道自己是属于哪一个共享指针。这样说可能有点绕。

    1.如何使用TSharedFromThis

    代码如何书写如下, 可以看到我继承了: public TSharedFromThis 。继承了这个类其实里面会多一个WeakPtr,存了一个弱引用对象,或者可以叫或引用关系。
    在这里插入图片描述

    class ClassBase : public TSharedFromThis<ClassBase>
    {
    public:
    	int32 nBase;
    };
    
    class ClassTop : public ClassBase
    {
    public:
    	void MyFunc() {}
    };
    

    有了这个,我们可以直接new出来的原生类上就有了AsShared方法,会存着一个这个类的共享引用。
    方便我们直接做转换。比如如下代码

    AsShared使用案例

    //如何使用继承自TSharedFromThis的类
    void MySharedFromThisTest();
    
    //如何使用继承自TSharedFromThis的类
    void AMyActor::MySharedFromThisTest()
    {
    	TSharedPtr<ClassTop> ptr = MakeShareable(new ClassTop());
    	if (ptr.IsValid())
    	{
    		//我们通过.Get()将TSharedPtr转换成C++ 原生指针
    		ClassTop* pOriginPtr = ptr.Get();
    
    		//现在我们想将pOriginPtr这个原生C++指针怎么转回智能指针呢?
    		{
    			//错误的用法, 也能这么用, 但是不建议
    			//TSharedPtr<ClassTop> ptr = MakeShareable(pOriginPtr);
    
    			//错误的用法, AsShared()不能用派生类接
    			//TSharedPtr<ClassTop> ptr22 = pOriginPtr->AsShared();
    		}
    		{
    			//正确的用法, AsShared()不能用基类接(基类指的是你继承自TSharedFromThis的那个类)
    			TSharedPtr<ClassBase> ptr2 = pOriginPtr->AsShared();
    			TSharedPtr<ClassTop> ptr3 = StaticCastSharedPtr<ClassTop>(ptr2);
    			if (ptr3.IsValid())
    			{
    				ptr3->MyFunc();
    			}
    		}
    	}
    }
    

    2.TSharedFromThis哪些场合适合使用?

    1>比如我们要写一个单例管理类,可以将数据类上继承自这个
    2>有转换成原生类的需求,又想在某一处将原生C++类再次转换成TSharedPtr的需求

    3.使用注意事项

    1>错误的用法, 也能这么用, 但是不建议

    TSharedPtr<ClassTop> ptr = MakeShareable(pOriginPtr);
    

    2>错误的用法, AsShared()不能用派生类接

    TSharedPtr<ClassTop> ptr22 = pOriginPtr->AsShared();
    

    3>正确的用法, AsShared()不能用基类接(基类指的是你继承自TSharedFromThis的那个类)

    TSharedPtr<ClassBase> ptr2 = pOriginPtr->AsShared();
    TSharedPtr<ClassTop> ptr3 = StaticCastSharedPtr<ClassTop>(ptr2);
    if (ptr3.IsValid())
    {
    	ptr3->MyFunc();
    }
    

    五.注意事项总结

    1>切记TSharedPtr/TSharedRef/TWeakPtr/TSharedFromThis都是不允许和UObject类一起混合使用的
    2>切记不能用UPROPERTY这些反射修饰符来修饰这些智能指针变量
    3>切记TSharedRef变量是不允许定义在头文件里面作为成员变量出现的
    4>以下四个C++的原生cast方法不适用于这里

    不能用于UE4智能指针的转换, 请使用
    ConstCastSharedRef/ConstCastSharedPtr/StaticCastSharedPtr/StaticCastSharedRef
    static_cast 
    dynamic_cast
    const_cast
    reinterpret_cast
    

    5>在UE4里面还是使用UE4的智能指针,就别用C++11的了,因为UE的智能指针能和UE的代码比如一些容器能够方便的使用。
    6>UE的智能指针要比C++占得字节要大
    7>这些智能指针都是支持线程安全的,有Fast和Safe两种模式。默认是Fast,也就是非线程安全。
    需要标记成Safe模式。回头我想再出一篇关于 UE4线程的内容 构思好把链接放这。
    8>TSharedFromThis本身是8字节。因为内置还有一个TWeakPtr,
    额外有一个16字节的引用控制器,TWeakPtr用起来比其他俩要慢。因为多了16字节。

    该部分的官方详细链接

    谢谢大家。有问题请指正。
    创作不易,大侠请留步… 动起可爱的双手,来个赞再走呗 <( ̄︶ ̄)>

    展开全文
  • C++中强指针和弱指针使用原则浅析

    千次阅读 2014-07-07 17:14:22
    使用C++开发大型项目时,指针的管理是ra
  • 相信大家对指针的用法已经很熟了,这里也不多说些定义性的东西了,只说一下指针使用中的注意事项吧。 一.在定义指针的时候注意连续声明多个指针时容易犯的错误,例如int * a,b;这种声明是声明了一个指向int类型...
  • 1、使用指针的第一件事就是需要看这个指针是否是空指针(坚决不能使用指针,否则程序就会蹦。意思就是:为一个指针赋值为空指针是不会报错的:char*p;但是在使用的时候一定要判断是否为空指针(即该指针有没有指向...
  • STM32指针使用

    千次阅读 2019-03-01 09:42:41
    CALCBILL_DATA_ST是个结构体占地址10个 uint8 txbuf1[10]={1,2,3,4,5,6,7,8,9,10}; ...uint8 txbuf2[10]={11,12,13,14...定义指针时一定要明确指针指向,否则就是野指针,尤其定义结构体或数组指针
  • 1、指针是地址,而不是具体的标量值,这是指针的精髓,不管是一级指针、二级 指针、 整型指针、浮点数指针、结构体指针等等等等所有类型的指针,内容都是个地址,而指针本身当然也是有地址的,而且容易忽略的是,...
  • 指针参数传递实质及二级指针使用

    千次阅读 多人点赞 2016-10-01 20:59:23
    水平有限,如有错误,欢迎指正,谢谢。 先看两个程序 : ...所以要对实参传进来的指针进行直接操作的话,就可以使用二级指针,把实参的地址传给二级指针,通过二级指针去改变一级指针的值。
  • C语言调用jni中JNIEnv指针使用和理解

    千次阅读 2017-04-04 22:59:56
    使用C语言调用jni的时候,需要和java的环境对象和虚拟机对象交互。它们的C语言定义如下。 typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; 可以看到,JNIEnv和...
  • 关注C++细节——浅谈指针使用中注意事项

    千次阅读 多人点赞 2011-09-02 09:52:08
    相信大家对指针的用法已经很熟了,这里也不多说些定义性的东西了,只说一下指针使用中的注意事项吧。 一.在定义指针的时候注意连续声明多个指针时容易犯的错误,例如int * a,b;这种声明是声明了一个指向int类型变量...
  • C++ Boost智能指针使用总结

    千次阅读 2019-07-17 23:11:22
    boost库智能指针使用详解概述scope_ptr特点用法scope_array特点用法shared_ptr特点weak_ptrintrusive_ptr 概述 C++没有提供类似JAVA的垃圾回收机制,因此boost通过智能指针用来管理内存避免一些问题。C++继承 C 高效...
  • C语言结构体与结构体指针使用

    千次阅读 多人点赞 2020-08-08 22:29:02
    C语言结构体与结构体指针使用 tips:最近要好好学习一下数据结构,所以必不可少的就是c语言的结构体和结构体指针了,所以就整理一下这些基础知识 c语言结构体(struct)是由一系列具有相同类型或不同类型的数据构成...
  • 我们重点来看一下二级指针使用方式。 我们知道,不管是几级 指针,本质上也是个普通变量,只不过指向的内容不同而已。二级指针指向的是“一级指针的地址”。 这里,参考博友二级指针的详解的里的图片,向作者...
  • 很多c++泛型算法以及linux库函数经常见到函数指针使用。。 函数指针的声明:bool (*pf)(int, int); //pf指向一个函数,该函数的参数是两个int,返回值是bool类型 函数指针的初始化例如有这样一个
  •   刚开始了解指针是从交换两个变量开始,但是总是断断续续地学,每次都在看交换两个变量的函数,上周在课上正式学了指针,看的时候感觉懂了,但是一上机就不知道指针怎么用、参数怎么传。于是想整理一下指针的学习...
  • C语言中二级指针使用

    千次阅读 2017-08-07 18:17:48
    C/C++中使用指针可以减少函数传递的参数 例如:typedef struct { int r[MAX]; int length; }SqList;调用void test(SqList s)函数时,会把结构体SqList拷贝一份传入函数,这样就使得效率变低。 使用指针可以传递...
  • 指针数组和数组指针使用

    千次阅读 2018-03-08 20:39:42
    指针数组:指针的数组,表示一个数组,并且数组的每一个元素都是指针类型。 数组指针:数组的指针,表示一个指针,并且是指向数组的指针。 不运行程序,问下面代码的输出是什么? 1#include&lt;iostream&...
  • 指针的详细使用介绍

    千次阅读 多人点赞 2018-07-13 11:38:09
    指针简介 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而...
  • C语言FILE指针使用方法

    千次阅读 多人点赞 2018-12-14 19:52:52
    C语言FILE指针使用方法 文章目录C语言FILE指针使用方法一、FILE指针1.定义2.文件类型分类3.文件打开方式4.文件打开5.文件关闭二、文件读写函数1.单字节的输入输出函数2.文件指针移动函数3.正文文件读/写函数三、...
  • 关于golang指针的理解与使用

    千次阅读 2019-01-05 16:16:39
    Go指针理解 Go 有指针,但是没有指针运算。你不能用指针变量遍历字符串的各个字节。在 Go 中调用函数的时候,得记得变量是值传递的。 通过类型作为前缀来定义一个指针’ * ’:var p * int。现在 p 是一个指向整数...
  • 指向结构体变量的指针与指向结构体数组的指针使用时的区别就是:指向结构体变量的指针,在使用时这样写:struct rsol v;struct rsol *m;m = &amp;v;指向结构体数组的指针,在使用时这样写:struct edc hj[5]={...
  • 静态或者全局智能指针使用的注意几点 在C++11普及开始后,智能指针才真正的被广大的C++程序员使用,当然一些高手还有大牛还是非常轻视智能指针的,咱们不谈那个。今天只谈一谈智能指针的全局化和静态化后需要注意的...
  • 好长一段时间没明白共享指针的理解和使用,今天认认真真查了一些资料,搞懂了很多。在这里整理了一下两个链接的内容。 主要参考链接: https://blog.csdn.net/u011866460/article/details/42027457 ...
  • 指针数组 首先从名字就可以知道这是一个数组,是存放指针的数组。 先看几种指针数组: int * 数组指针 函数指针 函数指针数组 指向函数指针数组的指针
  • c语言指针使用小练习

    千次阅读 2014-07-26 11:20:37
    #import void swap (int *a, int *b); void swap (int *a, int *b) { ...//通过改变指针指向得值来改变变量得数值 *a = *b; *b = temp; } int main(int argc, const char * argv[]) { //指
  • QSharedPoint智能指针使用

    千次阅读 2018-05-31 11:01:59
    QSharedPoint 智能指针,可以帮助管理C++...智能指针使用,需要在T类型,定义完整之后使用.即不能在T类型内,使用其智能指针.如下 ··· //例如 class E_APOS_TOOLS ExampleClass: public QObject { Q_...
  • 智能指针使用指针错误

    千次阅读 2017-08-24 21:18:03
    使用指针
  • 二维指针使用

    千次阅读 2018-10-12 19:50:11
    #include #include #include int main() { ...// p = (int **)malloc(10*...//p指向一个指针 p = new int[10]; for (int i = 0; i &lt; 10; i++) { // *(p + i ) = (int )malloc(10sizeof(int)); *(p...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,583,501
精华内容 633,400
关键字:

指针的使用