How to correct the char* coercive type conversion character in the overloaded class type?

Precautions when overloading type coercion

Take for example the coercion of the class type to the char* type. We all know that the coercion to the char* type is nothing more than overloading operator char*(), but what we often fail to notice is that when we perform the following programming, it will appear Unexpected phenomenon (error example):

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
class Person  
{  
private:  
    string name;  
    int age;  
public:  
    Person() = default;  
    Person(string name, int age);  
    Person(Person& obj);  
  
    operator char*();  
  
    ~Person() = default;  
};  
  
Person::Person(string name, int age)  
{  
    this->name = name;  
    this->age = age;  
}  
  
Person::Person(Person & obj)  
{  
    this->name = obj.name;  
    this->age = obj.age;  
}  
  
Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    return const_cast<char*>(sstr.str().c_str());  
}  
  
int main()  
{  
    Person Person_Obj1("张三", 19);  
    cout << Person_Obj1 << endl;  
}  

 

Output result: (all garbled)

 

Let's explore the reasons:

The reason for this is that what we return is a char* pointer to the temporary memory space, that is to say, when we return a pointer of the char* type (Note: when we overload the char* coercion, the class type The object will be implicitly converted to a char* variable for output during cout output) Before cout output, the memory space pointed to by the char* type pointer has been released, as shown in the following example:

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
char* ShowInf()  
{  
    ostringstream sstr("张三");  
    return const_cast<char*>(sstr.str().c_str()); // 返回指向临时存储空间的char*型指针  
}  
  
int main()  
{  
    cout << ShowInf() << endl;  // 输出之前伴随着ShowInf()函数生命的结束里面的临时变量已经被销毁
}  

 

Output result: (output garbled code)

 

Therefore, we make the following improvements to the overloaded program:

We add a new variable to the class type, the type of this variable is consistent with the return value of the cast operator we want to overload, that is

I want to overload the caster of the char* type, then I will define a char* variable in the class type to store the result of the cast.

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
class Person  
{  
private:  
    string name;  
    int age;  
    char* Output;   
public:  
    Person() = default;  
    Person(string name, int age);  
    Person(Person& obj);  
  
    operator char*();  
  
    ~Person() = default;  
};  
  
Person::Person(string name, int age)  
{  
    this->name = name;  
    this->age = age;  
}  
  
Person::Person(Person & obj)  
{  
    this->name = obj.name;  
    this->age = obj.age;  
}  
  
Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size()];  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  
  
int main()  
{  
    Person Person_Obj1("张三", 19);  
    cout << Person_Obj1 << endl;  
}  

 

Output result:

 

We see that the output results are normal. We compare the difference between the code in "before improvement" and "after improvement" operator char*():

Before improvement:

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    return const_cast<char*>(sstr.str().c_str());  // 返回指向临时存储区域的指针(临时变量其实就是在栈(stack)当中存储的变量,它会随着局部变量堆在函数的释放而被释放掉)
}  

 

 

After improvement:

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size()];  // 动态申请内存空间,将数据存在堆区(heap)中
    strcpy(this->Output, sstr.str().c_str());  // 将临时变量的值拷贝至堆区变量当中
    return this->Output;  // 输出堆区变量
}  

 

Therefore, we must remember in the future: the data of the corresponding type obtained by overloading the type conversion operator should be stored in this type of type, and should not return a temporary variable. Any operation that returns a temporary variable is not feasible.

Improved version again: release the requested memory space:

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
class Person  
{  
private:  
    string name;  
    int age;  
    char* Output;   
public:  
    Person() = default;  
    Person(string name, int age);  
    Person(Person& obj);  
  
    explicit operator char*();  
  
    void Cout();  
  
    ~Person();  
};  
  
Person::~Person()  
{  
    if (this->Output != nullptr) // 防止再次被释放引发错误  
    {  
        delete[] this->Output;  
    }  
}  
  
Person::Person(string name, int age)  
{  
    this->name = name;  
    this->age = age;  
}  
  
Person::Person(Person & obj)  
{  
    this->name = obj.name;  
    this->age = obj.age;  
}  
  
Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size() + 1]; // 申请内存空间的时候一定要多预留一个空间  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  
  
void Person::Cout()  
{  
    cout << static_cast<char*>(*this) << endl;  
    delete[] this->Output;  
    this->Output = nullptr;  
}  
  
int main()  
{  
    Person Person_Obj1("张三", 19);  
    Person_Obj1.Cout();  
} 

 

In the code, I made the following improvements:

Constructed an output function:

void Person::Cout()  
{  
    cout << static_cast<char*>(*this) << endl;  
    delete[] this->Output;  
    this->Output = nullptr;  
}

 

This function can be customized output, and we can also reclaim the dynamically allocated memory space.

Person::~Person()  
{  
    if (this->Output != nullptr) // 防止再次被释放引发错误  
    {  
        delete[] this->Output;  
    }  
} 

 

Be sure to include this code in the destructor to prevent the memory that has been released from being released again.

 explicit operator char*();

​​​​​​​  

I declared the overloaded char* caster as an explicit type, and told the system not to perform implicit type conversion. This operation can prevent memory leaks caused by this->Output requesting memory space during implicit type conversion.

During the operation, I encountered the following problems:

CRT detected that the application wrote to memory after end of heap buffer

What this sentence tells us is: the memory space you released exceeds the length of its own, which means that the last element of your char type array is not caused by'\0', and there is no end to the free memory space, which leads to an error. So I made the following improvements:

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size() + 1]; // 申请内存空间的时候一定要多预留一个空间  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  

 

I reserved one more application space for this->Output to place the end flag of the'\0' character array. In the case of improvement, I obviously did not do this. My improvement code is as follows:

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size()];  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  

 

We question: Why is there nothing in this code?

Because our destructor did not release the memory space pointed to by this->Output, why?

Because I did not define the destructor ~Person() to release the memory space pointed to by this->Output, I used the system default destructor "~Person=default", so this code dynamically applies for the memory space Will be released as the entire program ends.

We also questioned: Why does not cause the "over-release" error when releasing the entire program?

The reason for our error is that the memory space we freed touched the interests of other storage units in the program, so the program will report an error, but when we release the entire program, there is no problem of who infringes on who’s interests. Anyway, all the benefits (memory occupied) are all released.

Guess you like

Origin blog.csdn.net/weixin_45590473/article/details/112252878