1. ホーム
  2. c++

[解決済み】C++ Exception thrown: read access violation.これはnullptrでした。

2022-02-06 09:34:07

質問

プログラミングの授業で、講師が自ら作成したストレステストを実行できるプログラムを設計することが要求されています。

私たちはノードとリンクリストを扱っていますが、このテーマについて私が見たどのYouTubeのビデオとも異なる方法で取り組んでいます。

ここ2、3日、自分のプログラムのどこがおかしいのか、髪をかきむしりながら考えているのですが、なかなかうまくいきません。

以下は、私のNode.cppファイルのコードです(Node.hをインクルードしていません)。

#include "Node.h"

Node::Node() {
    m_value = 0;
    m_next = nullptr;
}

void Node::setValue(int val) {
    m_value = val;
}

int Node::getValue() const {
    return m_value;
}

void Node::setNext(Node* prev) {
    m_next = prev;
}

Node* Node::getNext() const {
    return m_next;
}

以下は私のLinkedList.cppです。

#include <iostream>
#include <vector>
#include "LinkedList.h"

LinkedList::LinkedList() {
    m_front = nullptr;
    m_size = 0;
}

LinkedList::~LinkedList() {
    // Deconstructor
    m_size = 0;
    Node* a = m_front;
    Node* b = a->getNext();
    while (a->getNext() != NULL) {
        delete a;
        a = b;
        b = b->getNext();
    }
    delete a;
    a = NULL;
}

bool LinkedList::isEmpty() const{
    if (m_size == 0) {
        return true;
    }
    else {
        return false;
    }
}

int LinkedList::size() const {
    return m_size;
}

bool LinkedList::search(int value) const {
    if (m_size == 0) {
        return false;
    }
    else if (m_size == 1) {
        if (m_front->getValue() == value) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
        Node* a = m_front;

        for (int i = 0; i < m_size; i++) {
            if (a->getValue() == value) {
                return true;
            }
            else {
                a = a->getNext();
            }
        }
        return false;
    }
}

void LinkedList::printList() const {
    std::cout << "List: ";
    if (m_size == 0) {
        // Print Nothing
    }
    else if (m_size == 1) {
        std::cout << m_front->getValue();
    } 
    else {
        Node* a = new Node();
        a = m_front;
        int b = m_front->getValue();
        std::cout << b << ", ";

        while (a->getNext() != NULL) {
            a = a->getNext();

            if (a->getNext() == NULL) {
                std::cout << a->getValue();
            }
            else {
                std::cout << a->getValue() << ", ";
            }
        }
    }
    std::cout << std::endl;

}

void LinkedList::addBack(int value) {
    Node* a = new Node();
    a->setValue(value);
    if (m_size == 0) {
        m_front = a;
    }
    else {
        Node* b = new Node();
        b = m_front;
        while (b->getNext() != NULL) {
            b = b->getNext();
        }
        b->setNext(a);
    }
    m_size++;
}

void LinkedList::addFront(int value) {
    Node* a = new Node(); // Check later

    a->setNext(m_front);
    a->setValue(value);
    m_front = a;
    m_size++;

}

bool LinkedList::removeBack() {
    if (m_size == 0) {
        return false;
    }
    else {
        Node* a = new Node();
        Node* b = new Node();
        a = m_front;
        while (a->getNext() != NULL) {
            b = a;
            a = a->getNext();
        }
        b->setNext(nullptr);
        delete a;
        a = NULL;
        m_size--;
        return true;
    }
}

bool LinkedList::removeFront() {
    if (m_size == 0) {
        return false;
    }
    else {
        Node* a = new Node();
        a = m_front;
        m_front = m_front->getNext();
        delete a;
        a = NULL;
        m_size--;
        return true;
    }
}
std::vector<int> LinkedList::toVector() const {
    if (m_size == 0) {
        std::vector<int> b;
        return b;
    }
    else {
        std::vector<int> a(m_size);
        Node* b = new Node();
        b = m_front;
        for (int i = 0; i < m_size; i++) {
            a[i] = b->getValue();
            b = b->getNext();
        }
        return a;
    }
}

基本的に、私は自分でプログラムをテストして、リンクリストを作り、すべての追加と削除の関数を実行し、リストをうまく印刷することができました。問題は、講師が出したテストを実行したところ、以下のように表示され、問題が発生しました(これらの印刷メッセージは別のファイルにありますが、これらは渡された文字列引数を印刷しているようにしか見えません)。

int score = 0;
const int MAX_SCORE = 90;

std::cerr << "\n\n=========================\n";
std::cerr << "   RUNNING TEST SUITE    \n";
std::cerr << "=========================\n\n";

//Run test and award points where appropriate
score += test1() ? 2 : 0; 
score += test2() ? 2 : 0; 
score += test3() ? 3 : 0; 

このテストは18回行われますが、私のプログラムは決して最初のテストを通過することができません。最初のテストに合格すると、突然エラーを投げます。

bool Test_LinkedList::test1()
{
    LinkedList list;
    bool isPassed = false;

    printTestMessage("size of empty list is zero"); 

    isPassed = list.size() == 0;
    printPassFail(isPassed);

    return (isPassed);
}

実際にクラッシュする前に、このような出力が得られました。

=========================
   RUNNING TEST SUITE
=========================

Test 1: size of empty list is zero: PASSED

つまり、最初のテストはパスするものの、そこから先には進めないということです。どういうことかというと、次のようなcoutメッセージを投げてみたのです。

score += test1() ? 2 : 0; 
std::cout << "Done with test 1"
score += test2() ? 2 : 0; 
score += test3() ? 3 : 0; 

しかし、それが出力されることはない。代わりに、私のプログラムは壊れ、Visual Studioは次のようなメッセージをポップアップ表示します。

Exception thrown: read access violation.

this was nullptr.

If there is a handler for this exception, the program may be safely continued.

そして、Node.cppにある私のメソッドを指し示します。

Node* Node::getNext() const {
    return m_next;
}

すみません、読み切れないほどの文章ですが、今、困っているのを通り越して、明日の早朝が締め切りなので、オフィスアワーに行く時間がないのです。

edit: 最初のテストを省いて実行してみました。次の6つのテストは通過しましたが、7つ目(8つ目)で全く同じエラーで失敗します。

bool Test_LinkedList::test8()
{
    LinkedList list;
    bool isPassed = false;

    printTestMessage("search returns false on empty list");

    isPassed = !list.search(42);
    printPassFail(isPassed);
    return (isPassed); 
}

解決方法は?

その LinkedList デストラクタにはいくつかの問題があります。まず m_size から 0a から NULL というのも、デストラクタが終了した時点で両方とも消えてしまうからです。さらに重要なことは、リストが空のとき、コードはヌルポインタを参照解除しようとすることです。

Node* a = m_front; // okay, gets that head pointer
Node* b = a->getNext(); // bang!!

もっとすっきりした書き方はこちらです。

Node* a = m_front;
while (a != NULL) {
    Node *temp = a->getNext();
    delete a;
    a = temp;
}