C++ “抛出未处理的异常:读取访问冲突。_First was nullptr”错误是什么意思?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38278622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does "Unhandled exception thrown: read access violation. _First was nullptr" error mean?
提问by Felix Chang
I compiled my code, but it threw me "Exception thrown: read access violation. _First was nullptr."
我编译了我的代码,但它向我抛出“异常抛出:读取访问冲突。_First 是 nullptr。”
I literally have no idea what this means as I'm still a beginner in C++. I really need your help to figure this problem as I've been struggling with this code for days, and it's so frustrating...
我真的不知道这意味着什么,因为我仍然是 C++ 的初学者。我真的需要你的帮助来解决这个问题,因为我已经为这段代码苦苦挣扎了好几天,这太令人沮丧了......
Thank you in advance.
先感谢您。
#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;
}
回答by Barmar
Your copy constructor never sets the target's value
, so when you try to use the new string, value
is uninitialized. Instead of using the local variable newCopy
, you should assign to value
.
您的复制构造函数从不设置目标的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];
}
}
Also, the constructor that takes char* chars
must make a copy of chars
. Otherwise, the pointer could become invalid if the parameter was a local array that has gone out of scope, or a dynamic array that was deleted. Also, since the destructor does delete[] value;
, it requires that this be dynamically-allocated, which wouldn't be correct when you initialize it from string literals.
此外,采用的构造函数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];
}
}
回答by Aconcagua
There is a whole series of issues to address:
有一系列问题需要解决:
First, you allow value
to be 0/NULL/nullptr (best use the new c++11 nullptr keyword!). If you do so, you need to consider this possibility in every function and operator, else you will try to access an invalid memory location (e. g. when doing strlen(value)
). Exactly this is what the exception means (0 is no valid memory address in most cases, some exceptions exist for embedded systems - where you might, however, break the entire system if writing to it!): you ran into such a situation.
首先,您允许value
为 0/NULL/nullptr(最好使用新的 c++11 nullptr 关键字!)。如果这样做,您需要在每个函数和运算符中考虑这种可能性,否则您将尝试访问无效的内存位置(例如,在执行 时strlen(value)
)。这正是异常的含义(在大多数情况下,0 不是有效的内存地址,嵌入式系统存在一些异常 - 但是,如果写入它,您可能会破坏整个系统!):您遇到了这种情况。
To avoid this hassle in every function/operator, you might prefer to always set value
to an existing empty string aready in the constructor, just as std::string does (exception: not every implementation of std::string does accept std::string(nullptr)
). You avoid another problem for the user, too: you enabled him to get two different string representations for string of size 0: nullptr
and ""
.
为了避免在每个函数/运算符中出现这种麻烦,您可能更喜欢value
在构造函数中始终设置为现有的空字符串区域,就像 std::string 所做的那样(例外:并非 std::string 的每个实现都接受std::string(nullptr)
)。您也为用户避免了另一个问题:您使他能够为大小为 0:nullptr
和 的字符串获取两种不同的字符串表示形式""
。
Another issue is that you are notcopying the string in case of the constructor acceptying char*
, but deleting it in the destructor. Problem: the argument could be a char buffer allocated on the stack:
另一个问题是,在构造函数接受的情况下,您不会复制字符串char*
,而是在析构函数中将其删除。问题:参数可能是在堆栈上分配的字符缓冲区:
char buffer[64];
/* ... */
return MyString(buffer);
It might be efficient to take owner ship of an existing string in many cases (something impossible with std::string – safe in every situations, inefficient in some), but you can get deep problems in others (as above, or if assigning a string literal return MyString("hello world");
(OK, this is problematic anyway, as literals are char const*
in C++ - but many compilers let you get away with it, just raising a warning). If you wanted to allow taking ownership, I would not do it by default (copy the string), and add another constructor explicitely allowing it (MyString(char*, bool takeOwnership = false)
, together with (MyString(char const*)
always copying - note the const
). Of course, you need to remember somewhere, if you have ownership. Only delete the internal representation, if you have ownership (the default...).
在许多情况下,拥有现有字符串的所有权可能是有效的(std::string 不可能实现 - 在所有情况下都是安全的,在某些情况下效率低下),但在其他情况下您可能会遇到深层次的问题(如上所述,或者如果分配一个字符串文字return MyString("hello world");
(好吧,无论如何这都是有问题的,因为文字char const*
在 C++ 中 - 但许多编译器让你逃脱它,只是发出警告)。如果你想允许拥有所有权,我不会默认这样做(复制string),并添加另一个明确允许它的构造函数 ( MyString(char*, bool takeOwnership = false)
, 以及 (MyString(char const*)
总是复制 - 注意const
)。当然,如果您拥有所有权,您需要记住某处。如果您拥有所有权(默认值),则仅删除内部表示。 ...)。
You are comparing the char*
values via ==, !=, <, >, ... operators. Be aware that you get equality only if both value
members point to exactly the same string, but not, if two different strings are literally equal:
您正在char*
通过 ==、!=、<、>、... 运算符比较这些值。请注意,只有当两个value
成员指向完全相同的字符串时,您才能获得相等性,但如果两个不同的字符串字面上相等,则不会:
char b1[] = {'a', 'b', 'c', 0 };
char b2[] = {'a', 'b', 'c', 0 };
bool isEqual = MyString(b1) == MyString(b2);
isEqual
will be false
! I assume you did not intend this, rather the same behaviour as std::string provides. An even more serious problem are the operators <, <=, >, >=. It is legal to compare with these only if both pointers point to the same array or one past the end (b3 = b1 + 2
), otherwise, it is undefined behaviour.
isEqual
会false
!我假设您不打算这样做,而是与 std::string 提供的行为相同。更严重的问题是运算符 <、<=、>、>=。只有当两个指针都指向同一个数组或一个数组末尾 ( b3 = b1 + 2
) 时,才可以与这些进行比较,否则,这是未定义的行为。
To get the behaviour I assume you want to have, you need to use strcmp
:
要获得我假设您想要的行为,您需要使用strcmp
:
bool operator X(MyString const& l, MyString const& r)
{
return strcmp(l, r) X 0;
}
Where you replace X with the appropriate operator (note that you can define !=
as !(l == r)
, <=
as !(l > r)
, etc.).
用适当的运算符替换 X 的地方(请注意,您可以定义!=
as !(l == r)
、<=
as!(l > r)
等)。
And please, please, please: Don't do such stuff as:
拜托,拜托,拜托:不要做这样的事情:
if(a == b)
return true;
else
return false;
or
或者
bool isWhatEver;
if(c != d)
isWhatEver = true;
else
isWhatEver = false;
Simply write
简单地写
return a == b;
isWhatEver = c != d;
Addendum:
附录:
You are violating the rule of three, you did not provide an assignment operator: operator=(MyString const& other)
. The rule of three actually became the rule of fivewith C++11; you might want to add a move constructor and a move assignment operator, too. Before implementing, have a look at here, that might be very useful for you...
您违反了三规则,您没有提供赋值运算符:operator=(MyString const& other)
。三的规则实际上变成了C++11的五规则;您可能还想添加一个移动构造函数和一个移动赋值运算符。在实施之前,看看这里,这可能对你非常有用......
Edit:
编辑:
It is almost impossible to tell just from the address, what went wrong. You did not provide any stack trace and not fixed code of yours...
仅从地址几乎不可能知道出了什么问题。您没有提供任何堆栈跟踪,也没有提供您的固定代码......
So I allowed myself to fix your class to what I think you might have intended. This version ran through all of your tests, at least, content of the input file was simply 'hello world'. Left out move constructor (hint: use std::swap for this). I still do not guarantee it to be bugfree... Some advise: don't just take my code, have a close look at what I did differently to see what might have gone wrong. One last thing: I made operator>> safe against failure because of exceeding buffer size using an std::vector.
所以我允许自己按照我认为你可能想要的方式调整你的课程。这个版本运行了你所有的测试,至少,输入文件的内容只是“hello world”。省略了移动构造函数(提示:为此使用 std::swap)。我仍然不保证它没有错误......一些建议:不要只拿我的代码,仔细看看我做了什么不同的事情,看看可能出了什么问题。最后一件事:由于使用 std::vector 超出缓冲区大小,我使 operator>> 安全避免失败。
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;
}