Interview Question 1: Assignment Operator Functions

Topic: The following is the declaration of the type CMyString, please add an assignment operator function to this type

class CMyString
{
public:
    CMyString(char* pData = nullptr);
    CMyString(const CMyString& str);
    ~CMyString(void);
private:
    char* m_pData;
};

Faced with this type of question, interviewers usually focus on the following points when examining the code written by the candidate:

  • Whether to declare the return type as a reference to that type, and return a reference to the instance itself (*this) before the function ends. Continuous assignment is allowed only if a reference is returned. Otherwise, if the return value of the function is void, applying the assignment operator will not allow continuous assignment. Suppose there are 3 CMyString objects: str1
    , str2, str3, the statement str1=str2=str3 in the program will not pass compilation.

  • Whether to declare the type of the passed parameter as a constant reference. If the parameter passed in is not a reference but an instance, the copy constructor will be called once from the formal parameter to the actual parameter. Declaring parameters as references can avoid such unnecessary
    consumption and improve the efficiency of the code. At the same time, we will not change the state of the incoming
    instance , so we should add the const keyword to the incoming reference parameter.

  • Whether to free the memory that the instance itself has. If we forget to free the space we already have before allocating new memory, the program will have a memory leak.

  • Determine whether the incoming parameter and the current instance (*this) are the same instance. If it is the same, no assignment operation is performed, and it is returned directly. If the assignment is made without prior judgment, it will cause serious problems when releasing the memory of the instance itself: when *this and the incoming parameter are the same instance, once the memory of the incoming parameter is released, the memory of the incoming parameter will also be At the same time, it is freed, so the content that needs to be assigned can no longer be found.

  • Classic solution, suitable for junior programmers

CMyString& CMyString::operator=(const CMyString &str)
{
    if(this==&str)
        return *this;
    delete []m_pData;
    m_pData = nullptr;

    m_pData = new char[strlen(str.m_pData)+1];
    strcpy(m_pData,str.m_pData);
    return *this;
}
  • The above solution is still inappropriate, we first use delete to release the memory of the instance m_pData. If the new char throws an exception due to insufficient memory at this time, m_pData will be a null pointer, which is very easy to cause the program to crash. That is, once an exception is thrown inside the assignment operator function, the instance of CMyString no longer remains in a valid state, which violates the principle of exception safety.

Solution:

CMyString& CMyString::operator=(const CMyString &str)
{
    if(this!=&str)
    {
        CMyString strTemp(str);//创建一个临时实例strTemp
        char* pTemp = strTemp.m_pData;
        strTemp.m_pData = m_pData; //将strTemp.m_pData和实例自身的m_pData进行交换
        m_pData = pTemp;
    }
    return *this;
}

Source code for this topic:

#include<cstring>
#include<cstdio>

class CMyString
{
public:
    CMyString(char* pData = nullptr);
    CMyString(const CMyString& str);
    ~CMyString(void);

    CMyString& operator = (const CMyString& str);

    void Print();

private:
    char* m_pData;
};

CMyString::CMyString(char *pData)
{
    if(pData == nullptr)
    {
        m_pData = new char[1];
        m_pData[0] = '\0';
    }
    else
    {
        int length = strlen(pData);
        m_pData = new char[length + 1];
        strcpy(m_pData, pData);
    }
}

CMyString::CMyString(const CMyString &str)
{
    int length = strlen(str.m_pData);
    m_pData = new char[length + 1];
    strcpy(m_pData, str.m_pData);
}

CMyString::~CMyString()
{
    delete[] m_pData;
}

CMyString& CMyString::operator = (const CMyString& str)
{
    if(this == &str)
        return *this;

    delete []m_pData;
    m_pData = nullptr;

    m_pData = new char[strlen(str.m_pData) + 1];
    strcpy(m_pData, str.m_pData);

    return *this;
}

// ====================测试代码====================
void CMyString::Print()
{
    printf("%s", m_pData);
}

void Test1()
{
    printf("Test1 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    CMyString str2;
    str2 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str2.Print();
    printf(".\n");
}

// 赋值给自己
void Test2()
{
    printf("Test2 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    str1 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str1.Print();
    printf(".\n");
}

// 连续赋值
void Test3()
{
    printf("Test3 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    CMyString str2, str3;
    str3 = str2 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str2.Print();
    printf(".\n");

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str3.Print();
    printf(".\n");
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();

    return 0;
}
  • Special Note: This article refers to He Haitao's book "Sword Pointing Offer"

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325983453&siteId=291194637