Ce n' “Unhandled exception: violation d'accès en lecture. _First était nullptr” erreur signifie?
J'ai compilé mon code, mais il m'a jeté "Exception: violation d'accès en lecture.
_First était nullptr."
J'ai littéralement n'ai aucune idée de ce que cela signifie que je suis encore un débutant en C++. J'ai vraiment besoin de votre aide pour comprendre ce problème que j'ai eu du mal avec ce code, pour les jours, et c'est tellement frustrant...
Vous en remercie d'avance.
#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;
}
- Donc, dans quelle mesure pensez-vous obtenir avant le message d'erreur s'affiche?
- Vous essayez de faire quelque chose avec la chaîne de caractères pointée par
value
, maisvalue
estNULL
. - Vous avez essayé de marcher avant de pouvoir courir - ce code est un gâchis. Pas de nulle contrôles,
operator+
a de nombreux bugs - il ne devrait même pas compiler puisque vous utilisez unconst MyString
comme premier argument de strcat, jamais l'esprit questrcat
exige que le tampon de destination être assez grand pour recevoir le deuxième texte supplémentaire. Dansoperator+=
vous utiliseznewMemory
pour stocker l'ancienne adresse... Votreoperator>>
est bizarre, votre comparaison les opérateurs de comparer les pointeurs, et votre destructeur suppose que vous possédez le pointeur qui n'est pas le cas s'il est construit avecMyString(char* s)
.
Vous devez vous connecter pour publier un commentaire.
Votre constructeur de copie ne définit jamais la cible
value
, de sorte que lorsque vous essayez d'utiliser la nouvelle chaîne,value
est non initialisée. Au lieu d'utiliser la variable localenewCopy
, vous devez attribuer àvalue
.Aussi, le constructeur qui prend
char* chars
devez faire une copie dechars
. Sinon, le pointeur pourrait devenir invalide si le paramètre local de tableau qui a disparu hors de portée, ou un tableau dynamique qui a été supprimé. Aussi, depuis le destructeur nedelete[] value;
, il faut que ce soit allouée dynamiquement, ce qui ne serait pas correct lors de l'initialisation de littéraux de chaîne.Il y a toute une série de questions à l'adresse:
Tout d'abord, vous permettent
value
à 0/NULL/nullptr (meilleure utilisation de la nouvelle c++11 nullptr mot-clé!). Si vous le faites, vous devez tenir compte de cette possibilité dans chaque fonction et de l'opérateur, sinon vous essayez d'accéder à un emplacement de mémoire non valide (e. g. lorsque vous faitesstrlen(value)
). Exactement c'est ce que l'exception signifie (0 est pas une adresse mémoire valide dans la plupart des cas, il existe quelques exceptions pour les systèmes embarqués - où vous pouvez, cependant, briser l'ensemble du système s'écrit à lui!): vous avez couru dans une telle situation.Pour éviter ce tracas dans chaque fonction/opérateur, vous préférerez peut-être toujours ensemble
value
à une chaîne vide déjà dans le constructeur, tout comme std::string n' (exception: pas tous de la mise en œuvre de std::string n'accepterstd::string(nullptr)
). Vous éviter un autre problème pour l'utilisateur, trop: vous lui a permis d'obtenir deux différentes représentations de chaîne pour chaîne de taille 0:nullptr
et""
.Un autre problème est que vous êtes pas la copie de la chaîne dans le cas du constructeur acceptying
char*
, mais de le supprimer dans le destructeur. Problème: l'argument pourrait être un char buffer alloué sur la pile:Il pourrait être efficace pour prendre du propriétaire de navire d'une chaîne existante dans de nombreux cas (ce qui est impossible avec std::string – coffre-fort dans toutes les situations, inefficace dans certains), mais vous pouvez obtenir en profondeur des problèmes dans d'autres (comme ci-dessus, ou si l'affectation d'une chaîne littérale
return MyString("hello world");
(OK, c'est un problème de toute façon, comme des littéraux sontchar const*
en C++, mais de nombreux compilateurs laissez-vous sortir avec elle, juste en levant un avertissement). Si vous voulez autoriser la prise de possession, je ne le ferais pas par défaut (copie de la chaîne), et ajouter un autre constructeur explicitement ce qui lui permet (MyString(char*, bool takeOwnership = false)
, avec (MyString(char const*)
toujours la copie de la note de laconst
). Bien sûr, vous devez vous rappeler quelque part, si vous avez de la propriété. Supprimer uniquement la représentation interne, si vous avez de la propriété (la valeur par défaut...).Vous comparez les
char*
valeurs via ==, !=, <, >, ... les opérateurs. Sachez que vous obtenez de l'égalité seulement si les deuxvalue
les membres exactement la même chaîne, mais non, si les deux chaînes sont littéralement égalité:isEqual
serafalse
! Je suppose que vous n'avez pas l'intention, ou plutôt le même comportement que std::string fournit. Un problème encore plus grave sont les opérateurs < <=, >, >=. Il est légal de les comparer avec celles-ci, seulement si les deux pointeurs pointent vers le même tableau ou d'un passé la fin (b3 = b1 + 2
), sinon, c'est un comportement indéterminé.Pour obtenir le comportement je suppose que vous voulez avoir, vous devez utiliser
strcmp
:Où vous remplacez X par l'opérateur (notez que vous pouvez définir
!=
comme!(l == r)
,<=
comme!(l > r)
, etc.).Et s'il vous plaît, veuillez, s'il vous plaît: Ne pas faire de telles choses comme:
ou
Simplement écrire
Addendum:
Vous violez la la règle de trois, vous n'avez pas fourni un opérateur d'affectation:
operator=(MyString const& other)
. La règle de trois est devenu en réalité le la règle des cinq avec C++11; vous pouvez ajouter un constructeur de déplacement et un opérateur d'assignation de déplacement, trop. Avant de mettre en œuvre, ont un oeil à ici, qui pourraient être très utiles pour vous...Edit:
Il est presque impossible de dire à partir de l'adresse, ce qui n'allait pas. Vous n'avez pas à fournir toute trace de la pile et non pas fixe code de la vôtre...
Donc je me suis permis de corriger votre classe à ce que je crois vous pourriez avoir l'intention. Cette version a couru à travers tous vos tests, au moins, le contenu du fichier d'entrée était tout simplement "bonjour le monde'. À gauche en sortant constructeur de déplacement (conseil: utiliser des std::swap pour cela). Je n'ai toujours pas de garantie d'être sans bugs... Quelques conseils: ne prenez pas mon code, avez un oeil de près ce que j'ai fait différemment pour voir ce qui pourrait mal tourner. Une dernière chose: j'ai fait de l'opérateur>> de la sécurité contre l'échec en raison de dépassement de taille de la mémoire tampon à l'aide d'un std::vector.