• 【剑指offer】面试题一:赋值运算符函数


    题目:如下为类型 CMyString 的声明,请为该类型添加赋值运算符函数。

    类的声明如下:

     1 class CMyString
     2 {
     3 public:
     4     CMyString(char *pData = NULL);
     5     CMyString(const CMyString &str);
     6     ~CMyString();
     7     
     8 private:
     9     char *m_pData;
    10 };

    关于赋值运算符函数,我们应该从以下几个方面考虑:

    1、返回值:首先我们应该把返回值的类型声明为该类型的引用,并在函数结束前返回本身的引用。只有返回一个引用才能允许连续赋值,如 str1 = str2 = str3;

    2、参数:其次我们应该把传入的参数的类型声明为常量引用。

      传入的引用是为了避免从形参到实参调用的一次复制构造函数;这也就是传值与传引用的效率问题。

      传入的为常量从语义的角度出发,我们在赋值运算函数内并不希望改变传入的实例的状态,因此,应该为传入的引用参数加上 const 关键字。

    3、内存:我们需要实例释放自身已有的内存,如果我们王子在分配新内存之前释放掉自身已有的内存,就会造成内存泄露;

    4、自身赋值问题:最后我们需要判断传入的参数和当前的实例(*this)是否为同一个实例。如果为同一个,则不进行赋值操作。因为,赋值之前需要释放已有的内存,如果为同一实例,那么传入的参数的内存在当前实例释放内存的同时也被释放了,这样就无法找到需要赋值的内容了。

    一、基本的解法:

      1、判断传入的参数是否为当前的实例本身;

      2、就是释放掉当前实例(*this)的内存;

      3、进行赋值;

      4、返回实例(*this);

     1 CMyString& CMyString::operator=(const CMyString &str)
     2 {
     3     if(this == &str)
     4         return *this;
     5 
     6     delete []m_pData;
     7     m_pData = NULL;
     8     m_pData = new char[strlen(str.m_pData)+1];
     9     strcpy(m_pData, str.m_pData);
    10 
    11     return *this;
    12 }
    View Code

    二、考虑异常安全性的解法:

    解法一存在安全问题,考虑如下问题:

    我们在分配内存之前先用 delete 释放了实例 m_pData 的内存。 如果此时内存不足导致 new char 抛出异常,这样 m_pData 将会是一个空指针,这样非常容易导致程序崩溃。

    在这里,我们用借用一个临时变量来解决上述问题。具体步骤为:

    先用传入的参数创建一个临时变量tmp,接着用该临时变量tmp 与实例自身的 m_pData 数据做交换。由于tmp为一个局部变量,该段程序运行结束时就是自动调用tmp的析构函数,把tmp的内存释放掉。

    代码如下:

     1 CMyString& CMyString::operator=(const CMyString &str)
     2 {
     3     if(this != &str)
     4     {
     5         CMyString tmp(str);
     6 
     7         char *pTmp = tmp.m_pData;
     8         tmp.m_pData = m_pData;
     9         m_pData = pTmp;
    10     }
    11     return *this;
    12 }
    View Code

    三、完整的CMyString类的实现及测试代码:

    CMyString.hpp文件

     1 #ifndef CMYSTRING
     2 #define CMYSTRING 
     3 
     4 #include <string.h>
     5 
     6 class CMyString
     7 {
     8 public:
     9     CMyString();
    10     CMyString(char *pData);
    11     CMyString(const CMyString &str);
    12     CMyString& operator=(const CMyString &str);
    13     ~CMyString();
    14 
    15 private:
    16     char *m_pData;
    17 };
    18 
    19 CMyString::CMyString()
    20 :m_pData(new char[1])
    21 {
    22     m_pData = '';
    23 }
    24 
    25 CMyString::CMyString(char *pData)
    26  :m_pData(new char[strlen(pData)+1])
    27 {
    28     ::strcpy(m_pData, pData);
    29 }
    30 
    31 CMyString::CMyString(const CMyString &str)
    32  :m_pData(new char[strlen(str.m_pData)+1])
    33 {
    34     ::strcpy(m_pData, str.m_pData);
    35 }
    36 
    37 CMyString& CMyString::operator=(const CMyString &str)
    38 {
    39     if(&str != this)
    40     {
    41         CMyString tmp(str);
    42 
    43         char *cTmp = tmp.m_pData;
    44         tmp.m_pData = m_pData;
    45         m_pData = cTmp;
    46     }
    47     return *this;
    48 }
    49 
    50 CMyString::~CMyString()
    51 {
    52     delete m_pData;
    53 }
    54 
    55 #endif /*CMYSTRING*/
    View Code

    测试代码main.cpp:

     1 #include "CMyString.hpp"
     2 #include <iostream>
     3 #include <string>
     4 
     5 using namespace std;
     6 
     7 int main(int argc, char const *argv[])
     8 {
     9     CMyString myString;
    10 
    11     char tmp[] = "helloworld";    
    12     CMyString myString2(tmp);
    13 
    14     myString = myString2;
    15 
    16     CMyString m3(myString);
    17     
    18     return 0;
    19 }
    View Code 

    编译与执行:

    1 g++ -o mystring main.cpp
    2 ./mystring

    引申:

    题目:一个空类,编辑器默认为其生成几个函数?

    类的声明如下:

    class Empty
    {
    
    };

    在该类实例化以后,一般编辑器会为其自动生成 默认构造函数、赋值构造函数、赋值运算符函数和析构函数 四个函数,

    具体如下:

    class Empty
    {
    public:
        Empty();
        Empty(const Empty &e);
        Empty& operator=(const Empty &e);
        ~Empty();
    };
    View Code
  • 相关阅读:
    excel的最大行数和列数
    c# XElement linq filter
    Linq SequenceEqual
    C# log4net日志使用
    MYSQL中常用脚本
    常用资源网站
    mqtt模式Work 模式公平分发
    mqtt模式Direct 模式
    mqtt模式Work 模式轮询分发
    解决:com.alibaba:druid:jar:1.1.21 is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
  • 原文地址:https://www.cnblogs.com/xfxu/p/4562985.html
Copyright © 2020-2023  润新知