我编写了类myString,它覆盖了一些运算符。如果它在vs2013(Microsoft Virtual Studio 2013)中运行,结果是错误的。但如果它在devcpp中运行,结果是正确的。 为什么呢?
顺便说一句,我有调试,发现问题是realloc。 在vs2013中重新分配后,内存中存在的数据变为无效。
我的所有代码:
#include <iostream>
#include<string>
#include <stdlib.h>
#include <string.h>
using namespace std;
class myString{
public:
myString() :_str(NULL), length(0){};
myString(char* str);
friend myString& operator+(myString& str,char* s);
friend myString& operator+(myString& str, myString& s);
friend myString& operator+(myString& str, int num);
friend ostream& operator<<(ostream& out,myString& str);
void operator=(char* s);
void operator=(myString& s);
private:
char* _str;
int length;
};
myString::myString(char* str){
if (str == NULL){
_str = NULL;
length = 0;
return;
}
length = strlen(str);
_str = (char*)malloc(sizeof(char)*length);
strcpy(_str, str);
}
myString& operator+(myString& str, char* s){
if (s == NULL)
return str;
char* temp = (char*)realloc((void*)str._str, sizeof(char)*strlen(s));
if (temp == NULL){
cout << "error" << endl;
return str;
}
str.length += strlen(s);
strcat(temp, s);
str._str = temp;
return str;
}
myString& operator+(myString& str, myString& s){
if (s.length == 0 || s._str == NULL)
return str;
char* temp = (char*)realloc((void*)str._str, sizeof(char)*strlen(s._str));
if (temp == NULL){
cout << "error" << endl;
return str;
}
str.length += strlen(s._str);
strcat(temp, s._str);
str._str = temp;
return str;
}
myString& operator+(myString& str, int num){
char* s = (char*)malloc(sizeof(char) * 100);
itoa(num, s, 10);
/******problem! in vs2013, after realloc str._str become invalid.
But in devcpp everything is right. Why???******/
char* temp = (char*)realloc((void*)str._str, sizeof(char)*strlen(s));
if (temp == NULL){
cout << "error" << endl;
return str;
}
str.length += strlen(s);
strcat(temp, s);
str._str = temp;
return str;
}
void myString::operator=(char* s){
if (s == NULL)
return;
this->length += strlen(s);
this->_str = (char*)malloc(sizeof(char)*strlen(s));
strcpy(this->_str, s);
}
void myString::operator=(myString& s){
this->length = s.length;
this->_str = s._str;
}
ostream& operator<<(ostream& out, myString& str){
out << "string is:" <<str._str<<", length is:"<<str.length;
return out;
}
int main(){
myString str;
str = "hello world";
cout << str << endl;
str = str+ 123;
cout << str << endl;
system("pause");
return 0;
}
答案 0 :(得分:1)
您缺少myString
输入和析构函数的复制构造函数。而char*
输入的复制构造函数不会复制char数据。
您的operator+
运营商实施错误。 operator+
不应该修改输入参数,但是你是。您需要返回参数数据的新合并副本,而您没有这样做。
您的operator=
运营商也被错误地执行了。 char*
运算符忽略NULL输入,使目标字符串不被修改而不是清除它。同一个运算符正在递增length
而不是重新分配它。 myString
运算符取得输入数据的所有权而不是复制它,留下两个myString
个对象指向同一个物理内存块。两个操作员都有内存泄漏,他们在用新数据替换之前不会释放现有数据。他们都需要返回对已修改的myString
的引用。
您的运营商应该使用copy-and-swap idiom来确保安全。
尝试更像这样的东西:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
class myString
{
public:
myString();
myString(const myString &src);
myString(const char* src);
myString(const int src);
~myString();
myString& operator=(const myString& rhs);
myString& operator+=(const myString& rhs);
friend myString operator+(const myString& lhs, const myString& rhs);
friend std::ostream& operator<<(std::ostream& out, const myString& str);
private:
char* _str;
int length;
};
myString::myString()
: _str(NULL), length(0)
{
}
myString::myString(const myString& src)
: _str(NULL), length(0)
{
if ((src._str != NULL) && (src.length > 0))
{
length = src.length;
_str = new char[length + 1];
std::copy(src._str, src._str + length, _str);
_str[length] = 0;
}
}
myString::myString(const char* src)
: _str(NULL), length(0)
{
if ((src != NULL) && (*src != 0))
{
length = std::strlen(src);
_str = new char[length + 1];
std::copy(src, src + length, _str);
_str[length] = 0;
}
}
myString::myString(const int src)
: _str(NULL), length(0)
{
char temp[16] = {0};
std::itoa(src, temp, 10);
length = std::strlen(temp);
_str = new char[length + 1];
std::copy(temp, &temp[length], _str);
_str[length] = 0;
}
myString::~myString()
{
delete[] _str;
}
myString& myString::operator=(const myString& rhs)
{
myString temp(rhs);
std::swap(_str, temp._str);
std::swap(length, temp.length);
return *this;
}
myString& myString::operator+=(const myString& rhs)
{
myString temp;
temp.length = length + rhs.length;
temp._str = new char[temp.length + 1];
std::copy(_str, _str + length, temp._str);
std::copy(rhs._str, rhs._str + rhs.length, temp._str + length);
temp._str[temp.length] = 0;
std::swap(_str, temp._str);
std::swap(length, temp.length);
return *this;
}
myString operator+(const myString& lhs, const myString& rhs)
{
myString temp;
temp.length = lhs.length + rhs.length;
temp._str = new char[temp.length + 1];
std::copy(lhs._str, lhs._str + lhs.length, temp._str);
std::copy(rhs._str, rhs._str + rhs.length, temp._str + lhs.length);
temp._str[temp.length] = 0;
return temp;
}
std::ostream& operator<<(std::ostream& out, const myString& str)
{
out << "string is: " << str._str << ", length is: " << str.length;
return out;
}
int main()
{
myString str;
str = "hello world";
std::cout << str << std::endl;
str = str + 123;
std::cout << str << std::endl;
std::system("pause");
return 0;
}
答案 1 :(得分:0)
据我了解realloc的操作,它可能会将内存移动到另一个地方 - 特别是如果它需要更多空间,它可能会使旧内存位置无效(解除分配)。
在此之后,记忆不再是“你的”。并且可能无法预测地改变。所以在我看来,VS2013的行为是在realloc的定义范围内 - 它只保证返回的内存是有效的(即你的temp
),而不是旧的内存地址将保持有效。
tldr:realloc可以破坏旧的内存位置;它在某些平台上工作的事实;是实施的结果,在许多记忆条件下都不可靠。