使用异常::what()时,cout打印了多余的字符。

3

我相信这很简单,但我无法想出一个搜索查询帮助我解决问题。

我几乎会认为这是Windows命令提示符中的错误,但除了当我使用exception::what()时才会发生此错误之外,我从未见过它。

这是为一项作业任务,程序应计算一系列给定的问题并显示答案。所有问题都是类似的(矩阵/向量算术),唯一会导致问题的是故意设计生成错误的问题,因为这是唯一使用exception::what()的时间。

以下是其中一个有问题的问题:

(顺便问一下,是否可以任意地将这些问题放入块中,以便对象超出范围并在下一个问题之前调用析构函数,就像我所做的那样?)

{ // Problem #9
    Vector v1(5);
    Matrix m1(3, 3, 1);
    try {
        v1.set(1, -2);
        v1.set(2, -1);
        v1.set(3, 4);
        v1.set(4, 9);
        v1.set(5, 3);
        m1.set(1, 1, 12);
        m1.set(1, 2, 36);
        m1.set(1, 3, -7);
        m1.set(2, 1, 4);
        m1.set(2, 3, 11);
        m1.set(3, 1, 7);
        m1.set(3, 2, -5);
        m1.set(3, 3, -2);
        Vector * ans9 = product(m1, v1);
        cout << "Answer to problem 9:" << endl;
        ans9->print();
        delete ans9;
    }
    catch(exception & ex) {
        cout << "Exception in problem 9: " << ex.what() << endl;
    }
} // End problem 9
cout << endl << endl;

Matrix类及其构造函数并没有什么特别的,代码在那里也没有抛出任何异常,所以现在我将分享有问题的product()函数:
Vector * product(Matrix &m, Vector &v) {
    unsigned int vLength = v.getLength(), mRows = m.getRows(), mCols = m.getCols();
    if ( mCols != vLength ) {
            throw std::logic_error("matrix/vector product impossible (size mismatch)!");
    }
    Vector * vprod = new Vector(mRows);
    for (unsigned int i = 1; i <= mRows; ++i) {
        double value = 0;
        for (unsigned int j = 1; j <= vLength; ++j) {
            value += (m.get(i, j)) * (v.get(j));
        }
        vprod->set(i, value);
    }

    return vprod;
}

这是我得到的输出示例:

screenshot

我在那里保留了感叹号,以便您可以看到它只是将最后一个字符直接打印在该列上,直到某些其他字符明确地打印在那里为止。

那么,到底发生了什么?我认为这可能与字符串终止有关,但也许这只是因为我过去太喜欢使用 C 了。

编辑:大家要求提供可编译的代码片段,我能做到的最好的就是 228 行。以下是代码:

#include <iostream>
#include <iomanip>
#include <cstdlib>

using std::cout;
using std::endl;
using std::exception;

class Vector {
    private:
    unsigned int length;
    double *elements;

    public:
    Vector(unsigned int desiredLength);

    ~Vector();

    //void dDestroy(Vector &v);

    unsigned int getLength();

    void set(unsigned int position, double value);

    double get(unsigned int position);

    void print();
};

Vector::Vector(unsigned int desiredLength) {
    length = desiredLength;
    elements = new double[length];
    for (unsigned int i = 0; i < length; ++i) {
        elements[i] = 0;
    }
}

Vector::~Vector() {
    delete[] elements;
}

unsigned int Vector::getLength() {
    return length;
}                    

void Vector::set(unsigned int position, double value) {
    if (position > length || position <= 0) {
        throw std::logic_error("vector set failed (out of range)");
    }
    --position;
    elements[position] = value;
}

double Vector::get(unsigned int position) {
    if (position > length || position <= 0) {
        throw std::logic_error("vector get failed (out of range)");
    }
    --position;
    return elements[position];
}

void Vector::print() {
    std::cout << "[  ";
    for (unsigned int i=0; i < length; ++i) {
        std::cout << elements[i] << "  " ;
    }
    std::cout << "]";
}

class Matrix {
    private:
    unsigned int rows, cols;
    double **elements;

    public:

    Matrix(unsigned int desiredRows, unsigned int desiredCols, double defaultValue);

    ~Matrix();

    unsigned int getRows();

    unsigned int getCols();

    void set(unsigned int i, unsigned int j, double value);

    double get(unsigned int i, unsigned int j);

    void print();
};

Matrix::Matrix(unsigned int desiredRows, unsigned int desiredCols, double defaultValue) {
    rows = desiredRows, cols = desiredCols;
    // Create
    elements = new double*[rows];
    for (unsigned int i = 0; i < rows; ++i) {
        elements[i] = new double[cols];
    }
    // Initialize
    for (unsigned int i = 0; i < rows; ++i) {
        for (unsigned int j = 0; j < cols; ++j) {
            elements[i][j] = defaultValue;
        }
    }
}

Matrix::~Matrix() {
    for (unsigned int i = 0; i < rows; ++i) {
        delete[] elements[i];
    }
    delete[] elements;
}

unsigned int Matrix::getRows() {
    return rows;
}

unsigned int Matrix::getCols() {
    return cols;
}

void Matrix::set(unsigned int i, unsigned int j, double value) {
    if (i > rows || j > cols) {
        throw std::logic_error("matrix set failed (out of range).");
    }
    --i, --j;
    elements[i][j] = value;
}

double Matrix::get(unsigned int i, unsigned int j) {
    if (i > rows || j > cols || i <= 0 || j <= 0) {
        throw std::logic_error("matrix get failed (out of range).");
    }
    --i, --j;
    return elements[i][j];
}

void Matrix::print() {
    // TODO it would be nice to format based on maximum digits in any value
    for (unsigned int i = 0; i < rows; ++i) {
        std::cout << "[  ";
        for (unsigned int j = 0; j < cols; ++j) {
            std::cout << std::setprecision(2) << elements[i][j] << "  ";
        }
        std::cout << "]\n";

    }
}

Vector * dot(Vector &v1, Vector &v2) {
    if (v1.getLength() != v2.getLength() ) {
        throw std::logic_error("dot product impossible (length mismatch)");
    }
    double result = 0;
    for (unsigned int i = 1; i <= v1.getLength(); ++i) {
        result += (v1.get(i) * v2.get(i));
    }
    Vector * vdot = new Vector(1);
    vdot->set(1, result);
    return vdot;
}

Vector * product(Matrix &m, Vector &v) {
    unsigned int vLength = v.getLength(), mRows = m.getRows(), mCols = m.getCols();
    if ( mCols != vLength ) {
        throw std::logic_error("matrix/vector product impossible (size mismatch)");
    }
    Vector * vprod = new Vector(mRows);
    for (unsigned int i = 1; i <= mRows; ++i) {
        double value = 0;
        for (unsigned int j = 1; j <= vLength; ++j) {
            value += (m.get(i, j)) * (v.get(j));
        }
        vprod->set(i, value);
    }

    return vprod;
}

Vector * dot(Vector &v1, Vector &v2);
Vector * product(Matrix &m, Vector &v);

int main() {
    cout << endl;

    { // Problem #1
    Vector v1(3), v2(3);
    try {
        v1.set(1, 2);
        v1.set(2, 1);
        v1.set(3, 3);
        v2.set(1, 0);
        v2.set(2, 4);
        v2.set(3, -9);

        Vector * ans1 = dot(v1, v2);
        cout << "Answer to problem 1:" << endl;
        ans1->print();
        delete ans1;
    }

    catch(const exception & ex) {
        cout << "Exception in problem 1: " << ex.what() << endl;
    }
    } // End problem 1
    cout << endl << endl;


    { // Problem #2
    Vector v1(2), v2(3);
    try {
        v1.set(1, 12);
        v1.set(2, 1);
        v2.set(1, 3);
        v2.set(2, -1);
        v2.set(3, 5);
        Vector * ans2 = dot(v1, v2);
        cout << "Answer to problem 2:" << endl;
        ans2->print();
        delete ans2;
    }
    catch(const exception & ex) {
        cout << "Exception in problem 2: " << ex.what() << endl;
    }

    } // End problem 2
    cout << endl << endl;
}

1
产生在(填充后的)行末的 ! 的代码在哪里? - wallyk
欢迎您。我想新手不允许上传图片是为了限制垃圾邮件攻击。您关于发布限制的评论应该放在meta上。 - wallyk
好的,这是一大堆代码,其中大部分都是不必要的。我能否只分享文件呢?不过我必须说,如果这确实是我的代码中的错误,那么我怀疑这个问题是由其他地方引起的。 - Marshall Eubanks
1
看起来很奇怪,也许你的内存被一些未显示的代码损坏了。尝试使用更少的代码重现问题,并向我们展示完整的代码片段,以便我们可以在本地尝试重现它。 - kan
好的,我已经发布了一个可编译的程序,在我的机器上至少显示了所讨论的行为。 - Marshall Eubanks
显示剩余8条评论
2个回答

1

好的,评论有点拥挤,而且以下内容对于评论来说有点太明确了,所以请原谅以下不完全是答案的风格。

由于额外的 "!" 也出现在提示符所在的行中,在程序已经退出后,它与您的应用程序几乎没有任何关系。可能是显示驱动程序出了问题,或者是客户端服务器运行时子系统/进程(csrss.exe)或控制台窗口主机(conhost.exe)出现了问题,这些都是在运行控制台应用程序时提供窗口的程序。 此外,如果屏幕截图没有误导,那么多余的字符(尤其是从“问题6”的右括号中可见)甚至没有完全重复,而只是部分重复。也就是说,该字符被某种方式“切断”了。

无论如何,您可以尝试一些步骤来进一步调查问题:

  1. 这只发生在你的系统上吗?
  2. 这只发生在64位进程上吗(我假设你从CMD标题中得知)?
  3. 如果你实际上没有抛出异常,比如:

    std::logic_error err("blah"); std::cout << err.what() << std::endl;

  4. 你能否更改程序使用stdio而不是iostreams?然后还会发生吗。

  5. 尝试将程序的输出重定向到文件中(例如“myapp.exe> foo.txt”)。文件中是否也包含额外的“!”。

我曾经在完全不同的情况下看到过这样的行为。

例子:

printf("12345678901234567890\r"); /* carriage return, but no linefeed */
printf("ABCDEFGHIJ\n");

这应该输出:

ABCDEFGHIJ1234567890

但是,我在你的代码中看不到类似的东西(iostreams vs. stdio或其他)。


谢谢你的回答。我明天得花些时间去探索你提出的问题的答案。 - Marshall Eubanks

0

你捕获异常时使用了 'exception &' 而不是 'const exception &',这让我感到担忧。'ex' 可能实际上指向已经被销毁的对象,因此 what() 方法返回垃圾值。你必须确保在 catch 处理程序中,'ex' 参数引用的是最初抛出的对象的有效副本。


2
虽然捕获一个const引用是一个好建议,但我怀疑它能解决问题。除非编译器有问题,否则被捕获的对象不应该被销毁。 - BЈовић
好的,我已经采纳了你的建议并开始使用“const exception&”。然而,这并没有解决问题。 - Marshall Eubanks
在执行传递给catch处理程序之前,我认为应该对对象进行复制,并且在执行catch处理程序之前销毁原始对象。 - bert-jan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接