什么是“未处理的异常抛出:读取访问冲突._First是nullptr”错误意味着什么?

时间:2016-07-09 05:16:21

标签: c++ c++11 pointers operator-overloading dynamic-memory-allocation

我编译了我的代码,但它告诉我“抛出异常:读取访问冲突。 _First是nullptr。“

我完全不知道这意味着什么,因为我还是C ++的初学者。我真的需要你的帮助才能解决这个问题,因为我几天来一直在努力解决这个问题,这太令人沮丧......

提前谢谢你。

#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;

class MyString {
public:

    //default constructor
    MyString();

    MyString(char* chars);

    //copy constructor
    MyString(const MyString &);

    int length() const;

    //destructor
    ~MyString();

    //operator overloads
    char& operator[](int index);
    friend MyString operator+(const MyString& newWord, const MyString& newWord2);
    MyString& operator+=(const MyString& newWord);
    friend ostream& operator<<(ostream& newWord, const MyString& newWord2);
    friend istream& operator >> (istream& newWord, MyString& newWord2);
    friend bool operator==(const MyString& newWord, const MyString& newWord2);
    friend bool operator!=(const MyString& newWord, const MyString& newWord2);
    friend bool operator<(const MyString& newWord, const MyString& newWord2);
    friend bool operator<=(const MyString& newWord, const MyString& newWord2);
    friend bool operator>(const MyString& newWord, const MyString& newWord2);
    friend bool operator>=(const MyString& newWord, const MyString& newWord2);

private:
    char* value;
    int size;
};

//default constructor
MyString::MyString() {

    value = NULL;
    size = 0;
}

//copy constructor
MyString::MyString(const MyString& newWord) {

    //perform a deep copy to copy each of the value to a new memory
    size = newWord.size;
    char* newCopy = new char[size];

    for (int ii = 0; ii < size; ii++) {
        newCopy[ii] = newWord.value[ii];
    }
}

//constructor with an argument
MyString::MyString(char* chars) {

    //give the value and the size
    value = chars;
    size = strlen(chars);
}

//find length
int MyString::length() const {

    return size;
}

//find the value of each index
char& MyString::operator[](int index) {

    return value[index];
}

//operator + (concatenate)
MyString operator+(const MyString& newWord, const MyString& newWord2) {

    MyString concatenated;
    concatenated = strcat(newWord.value, newWord.value);
    return concatenated;

}

//operator += (append)
MyString& MyString::operator+=(const MyString& newWord) {

    char * newMemory = value;
    value = new char[strlen(value) + newWord.length() + 1];
    strcpy(value, newMemory);
    strcat(value, newWord.value);
    if (size != 0)
    {
        delete[] newMemory;
    }
    size = strlen(value);
    return *this;
}

//ostream operator
ostream& operator<<(ostream& newWord, const MyString& newWord2) {

    newWord << newWord2.value;
    return newWord;
}


//istream operator
istream& operator >> (istream& newWord, MyString& newWord2) {

    const int MAX = 100;
    char* ptr = new char[MAX];
    newWord >> ptr;
    newWord2 = MyString(ptr);
    delete ptr;
    return newWord;
}

//all boolean operators
bool operator==(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value == newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator!=(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value != newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator<(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value < newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator<=(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value <= newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator>(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value > newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

bool operator>=(const MyString& newWord, const MyString& newWord2) {
    if (newWord.value >= newWord2.value) {
        return true;
    }
    else {
        return false;
    }
}

//destructor to release memory
MyString::~MyString() {
    delete[] value;
}

void test_copy_and_destructor(MyString S) {
    cout << "test: copy constructor and destructor calls: " << endl;
    MyString temp = S;
    cout << "temp inside function test_copy_and_destructor: " << temp << endl;
}

int main() {

    MyString st1("abc abc");
    MyString st2("9fgth");

    cout << "Copy constructor , << operator" << endl;

    MyString  st3(st1);

    cout << "st3: " << st3 << endl;

    test_copy_and_destructor(st2);

    MyString  st4;

    cout << "operator + " << endl;

    st4 = st3 + st2;

    cout << "st4: " << st4 << endl;

    cout << "st1 + st2: " << (st1 + st2) << endl;

    cout << "operators  [ ] " << endl;

    for (int i = 0; i < st2.length(); i++)
        cout << st2[i] << " ";

    cout << endl;

    cout << "operators  += , ==, != " << endl;

    st2 += st1;

    if (st3 == st1)
        cout << "st3 and st1 are identical " << endl;
    else cout << "st3 and st1 are not identical " << endl;

    if (st2 != st1)
        cout << "st2 and st1 are not identical " << endl;
    else cout << "st2 and st1 are identical " << endl;

    cout << "operators  < , <=, >, >= " << endl;

    if (st2 < st1)
        cout << "st2 < st1 " << endl;
    else cout << "st2 is not less than st1 " << endl;

    if (st1 <= st2)
        cout << "st1 <= st2 " << endl;
    else cout << "st1 is not less than or equal to st2 " << endl;

    if (st1 > st2)
        cout << "st1 > st2 " << endl;
    else cout << "not (st1 >  st2) " << endl;

    if (st1 >= st2)
        cout << "st1 >= st2 " << endl;
    else cout << "not (st1 >=  st2) " << endl;

    cout << "operator >> " << endl;

    //Open the data file
    ifstream input("A9_input.txt");
    if (input.fail()) {
        cout << "unable to open input file A9_input.txt, Exiting..... ";
        system("pause");
        return 0;
    }
    MyString temp1;
    MyString temp2("aaa");
    input >> temp1;
    input >> temp2;
    cout << "first element of input file: " << temp1 << endl;
    cout << "second element of input file: " << temp2 << endl;
    input.close();

    cout << "MyString says farewell....." << endl;
    system("pause");
    return 0;
}

2 个答案:

答案 0 :(得分:1)

您的复制构造函数从不设置目标的value,因此当您尝试使用新字符串时,value未初始化。您应该分配给newCopy

,而不是使用本地变量value
MyString::MyString(const MyString& newWord) {

    //perform a deep copy to copy each of the value to a new memory
    size = newWord.size;
    value = new char[size];

    for (int ii = 0; ii < size; ii++) {
        value[ii] = newWord.value[ii];
    }
}

此外,使用char* chars的构造函数必须复制chars。否则,如果参数是超出范围的本地数组或已删除的动态数组,则指针可能变为无效。此外,由于析构函数执行delete[] value;,因此需要动态分配,这在从字符串文字初始化时不正确。

//constructor with an argument
MyString::MyString(char* chars) {

    size = strlen(chars);
    value = new char[size];
    for (int i = 0; i < size; i++) {
        value[i] = chars[i];
    }
}

答案 1 :(得分:0)

有一系列问题需要解决:

首先,允许value为0 / NULL / nullptr(最好使用新的c ++ 11 nullptr关键字!)。如果这样做,您需要在每个函数和运算符中考虑这种可能性,否则您将尝试访问无效的内存位置(例如,在执行strlen(value)时)。这正是异常的意思(0在大多数情况下没有有效的内存地址,嵌入式系统存在一些例外 - 但是,如果写入它,你可能会破坏整个系统!):你遇到了这种情况。 / p>

为了避免每个函数/运算符中的麻烦,您可能更喜欢始终将value设置为构造函数中的现有空字符串isady,就像std :: string一样(异常:不是每个std的实现: :string确实接受std::string(nullptr))。您也可以为用户避免另一个问题:您启用了他为大小为0的字符串获取两个不同的字符串表示形式:nullptr""

另一个问题是,如果构造函数接受char*,则复制字符串,但在析构函数中删除它。问题:参数可以是在堆栈上分配的char缓冲区:

char buffer[64];
/* ... */
return MyString(buffer);

在许多情况下获取现有字符串的所有者可能是有效的(使用std :: string是不可能的 - 在每种情况下都是安全的,在某些中效率低下),但是你可能会遇到深层问题在其他人中(如上所述,或者如果指定字符串文字return MyString("hello world");(好吧,无论如何这都是有问题的,因为文字在C ++中是char const* - 但是许多编译器让你逃脱它,只是提出警告如果你想允许取得所有权,我默认情况下不会这样做(复制字符串),并明确地添加另一个构造函数(MyString(char*, bool takeOwnership = false),同时(MyString(char const*)总是复制 - 注意const)。当然,如果你有所有权,你需要记住某个地方。如果你有所有权(默认......),只删除内部表示。

您正在通过==,!=,&lt;,&gt;,...运算符比较char*值。请注意,只有当两个value成员指向完全相同的字符串时才会获得相等,但是如果两个不同的字符串在字面上相等则不会:

char b1[] = {'a', 'b', 'c', 0 };
char b2[] = {'a', 'b', 'c', 0 };
bool isEqual = MyString(b1) == MyString(b2);

isEqual将是false!我假设您不打算这样做,而是与std :: string提供的行为相同。更严重的问题是运算符&lt;,&lt; =,&gt;,&gt; =。仅当两个指针指向同一个数组或者指向一个结尾(b3 = b1 + 2)时才与它们进行比较是合法的,否则,它是未定义的行为。

要获得我想要的行为,您需要使用strcmp

bool operator X(MyString const& l, MyString const& r)
{
    return strcmp(l, r) X 0;
}

使用适当的运算符替换X的位置(请注意,您可以将!=定义为!(l == r)<=定义为!(l > r)等。

请拜托,请:不要做这样的事情:

if(a == b)
    return true;
else
    return false;

bool isWhatEver;
if(c != d)
    isWhatEver = true;
else
    isWhatEver = false;

简单写一下

return a == b;

isWhatEver = c != d;

<强>附录:

您违反rule of three,未提供作业运算符:operator=(MyString const& other)。三个规则实际上变成了rule of five与C ++ 11;您可能还想添加移动构造函数和移动赋值运算符。在实施之前,请查看here,这可能对您非常有用......

修改

几乎不可能只从地址说出来,出了什么问题。你没有提供任何堆栈跟踪而不是你的固定代码...

所以我允许自己修改你认为你可能有意的课程。这个版本贯穿了你所有的测试,至少,输入文件的内容只是'hello world'。省略移动构造函数(提示:为此使用std :: swap)。我仍然不保证它是无错误的...有些建议:不要只是接受我的代码,仔细看看我做了什么不同,看看可能出了什么问题。最后一件事:我做了运营商&gt;&gt;因使用std :: vector超出缓冲区大小而安全地防止失败。

class MyString
{
public:

    //default constructor
    MyString();

    MyString(char const* chars);

    //copy constructor
    MyString(const MyString &);

    int length() const;

    //destructor
    ~MyString();

    //operator overloads
    char& operator[](int index);
    friend MyString operator+(const MyString& newWord, const MyString& newWord2);
    MyString& operator+=(const MyString& newWord);
    MyString& operator=(const MyString& newWord)
    {
        char* newValue = new char[newWord.size];
        delete value;
        value = newValue;
        size = newWord.size;
        memcpy(value, newWord.value, size);
        return *this;
    }
    MyString& operator=(char const* chars)
    {
        size_t newSize = strlen(chars);
        char* newValue = new char[newSize];
        delete value;
        value = newValue;
        size = newSize;
        memcpy(value, chars, size);
        return *this;
    }
    friend ostream& operator<<(ostream& newWord, const MyString& newWord2);
    friend istream& operator >>(istream& newWord, MyString& newWord2);
    friend bool operator==(const MyString& newWord, const MyString& newWord2);
    friend bool operator!=(const MyString& newWord, const MyString& newWord2);
    friend bool operator<(const MyString& newWord, const MyString& newWord2);
    friend bool operator<=(const MyString& newWord, const MyString& newWord2);
    friend bool operator>(const MyString& newWord, const MyString& newWord2);
    friend bool operator>=(const MyString& newWord, const MyString& newWord2);

private:
    char* value;
    int size;
};

//default constructor
MyString::MyString()
{
    value = new char[1];
    *value = 0;
    size = 0;
}

//copy constructor
MyString::MyString(const MyString& newWord)
{
    //perform a deep copy to copy each of the value to a new memory
    size = newWord.size;
    value = new char[size];
    memcpy(value, newWord.value, size);
}

//constructor with an argument
MyString::MyString(char const* chars)
{
    if(chars)
    {
        size = strlen(chars);
        value = new char[size];
        memcpy(value, chars, size);
    }
    else
    {
        value = new char[1];
        *value = 0;
        size = 0;
    }
}

//find length
int MyString::length() const
{
    return size;
}

//find the value of each index
char& MyString::operator[](int index)
{
    return value[index];
}

//operator + (concatenate)
MyString operator+(const MyString& newWord, const MyString& newWord2)
{
    MyString concatenated;
    concatenated.value = new char[newWord.size + newWord2.size + 1];
    memcpy(concatenated.value, newWord.value, newWord.size);
    memcpy(concatenated.value + newWord.size, newWord2.value, newWord2.size + 1);
    return concatenated;
}

//operator += (append)
MyString& MyString::operator+=(const MyString& newWord)
{
    if(newWord.size > 0)
    {
        char * newMemory = value;
        value = new char[size + newWord.size + 1];
        memcpy(value, newMemory, size);
        memcpy(value + size, newWord.value, newWord.size);
        delete[] newMemory;
        size += newWord.size;
    }
    return *this;
}

//ostream operator
ostream& operator<<(ostream& newWord, const MyString& newWord2)
{

    newWord << newWord2.value;
    return newWord;
}

//istream operator
istream& operator >>(istream& newWord, MyString& newWord2)
{
    std::vector<char> v;
    for(;;)
    {
        char c = newWord.get();
        if(newWord.eof() || isspace(c))
        {
            break;
        }
        v.push_back(c);
    }
    if(!v.empty())
    {
        newWord2 = v.data();
    }
    return newWord;
}

//all boolean operators
bool operator==(const MyString& newWord, const MyString& newWord2)
{
    return strcmp(newWord.value, newWord2.value) == 0;
}

bool operator!=(const MyString& newWord, const MyString& newWord2)
{
    return !(newWord == newWord2);
}

bool operator<(const MyString& newWord, const MyString& newWord2)
{
    return strcmp(newWord.value, newWord2.value) < 0;
}
bool operator>(const MyString& newWord, const MyString& newWord2)
{
    return strcmp(newWord.value, newWord2.value) < 0;
}

bool operator<=(const MyString& newWord, const MyString& newWord2)
{
    return !(newWord > newWord2);
}

bool operator>=(const MyString& newWord, const MyString& newWord2)
{
    return !(newWord < newWord2);
}

//destructor to release memory
MyString::~MyString()
{
    delete[] value;
}