我正确初始化了非常小的矩阵,但其他矩阵给出了运行时错误

问题描述 投票:0回答:1

当我尝试初始化大多数矩阵对象时,我的代码给出了运行时错误。我测试了几种情况,将在下面展示。它只是说运行时错误,并没有解释测试系统中的情况,并且在我的 Windows 计算机上正确运行,返回退出代码 0。

我将首先给出导致错误的函数,并在底部给出相关的构造函数。这段代码通常应该执行卷积运算,但我禁用了一些部分来查找错误的根本原因。这就是我得到的:

// Test case 1
ImageMatrix Convolution::convolve(const ImageMatrix& input_image) const {
    int width = input_image.get_width();
    int height = input_image.get_height();
    ImageMatrix result(height, width, 0); // Gives runtime error
    // Some convolution logic disabled by commenting
    return result;
}

// Test case 2
ImageMatrix Convolution::convolve(const ImageMatrix& input_image) const {
    int width = input_image.get_width();
    int height = input_image.get_height();
    ImageMatrix result(1, 1, 0); // Runs correctly without error
    return result;
}

// Test case 3
ImageMatrix Convolution::convolve(const ImageMatrix& input_image) const {
    int width = input_image.get_width();
    int height = input_image.get_height();
    ImageMatrix result(3, 3, 0); // Gives runtime error
    return result;
}

// Test case 4
ImageMatrix Convolution::convolve(const ImageMatrix& input_image) const {
    int width = input_image.get_width();
    int height = input_image.get_height();
    ImageMatrix result(1, 1, 0);
    ImageMatrix kernel(2, 2, 1); // Runs correctly without error after the necessary change in the constructor
    return result;
}

// The constructors of the ImageMatrix class

// Constructor currently in use
ImageMatrix::ImageMatrix(int height, int width, double value) : height(height), width(width) {
    this->height = height;
    this->width = width;
    data = new double*[height];
    for (int i = 0; i < height; ++i) {
        data[i] = new double[width];
    }
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; j++) {
            data[i][j] = value;
        }
    }
}    for (int j = 0; j < width; j++) {
            data[i][j] = 0;
        }
    }
}

// Destructor
ImageMatrix::~ImageMatrix() {
    if (data) {
        for (int i = 0; i < height; ++i) {
            delete[] data[i];
        }
        delete[] data;
        data = nullptr;
    }
}
c++ matrix memory-leaks runtime-error
1个回答
0
投票

正如 @Eljay 在评论中报告的那样,您的构造函数和析构函数几乎没有问题。 Eljay 的说法可能是正确的,您的问题可能出在其他地方。

您提供的测试用例是一个可能的候选者。我无法理解它们的意义。在我看来,你对函数有四种不同的定义

Convolution::convolve
。这些是对函数
convolve
的调用,而不是定义吗?

无论如何,就使班级

Convolution
工作而言,班级
ImageMatrix
似乎是一种干扰,所以我在下面的程序中删除了它。

我发现的唯一缺陷是,如果调用运算符

new
抛出
std::bad_alloc
对象,构造函数将泄漏内存。我在下面修复了这个问题。


// The constructors of the ImageMatrix class
// Constructor currently in use
ImageMatrix::ImageMatrix(int height, int width, double value)
    : height(height), width(width)
{
    //this->height = height;  // redundant
    //this->width = width;    // redundant

    if (height <= 0)
        throw std::invalid_argument("ERROR: height is zero.");
    if (width <= 0)
        throw std::invalid_argument("ERROR: width is zero.");

    // This could throw std::bad_alloc.
    data = new double* [height];

    // Each call to `new` in the loop below could throw.
    // If any one of them does, then you must back out 
    // (i.e., delete) all of the allocations that were 
    // successful.
    //
    // If there is a throw, then variable `i` will hold the 
    // subscript that was not allocated. All subscripts less 
    // than `i` must have their allocations deleted.
    //
    // In addition, after a throw, you must deallocate the 
    // memory assigned to pointer `data`.
    // 
    // Those deallocations happen in the catch block.

    int i{};
    try {
        for (; i < height; ++i) {
            data[i] = new double[width];
        }
    }
    catch (std::bad_alloc const&) {
        while (i--)
            delete[] data[i];
        delete[] data;
        throw;
    }

    // Initialize
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; j++) {
            data[i][j] = value;
        }
    }
}

我坚持你对下标的选择

int
,而不是
std::size_t
。然而,我更喜欢使用
std::size_t

Class

ImageMatrix
是一个“3 或 5 规则”类,因此请务必提供我在代码中列出的缺少的“特殊”函数。

使用下面的程序,我能够分配测试用例中的所有矩阵。

// main.ixx
export module main;
import std;

class ImageMatrix
{
    double** data{ nullptr };
    int height{}, width{};
public:
    ImageMatrix() = default;
    ImageMatrix(int height, int width, double value = 0.0);

    // Rule of 5 (plus a noexcept swap function)
    //   1. destructor
    //   2. copy constructor - not yet coded
    //   3. move constructor - not yet coded
    //   4. copy-assignment operator - not yet coded
    //   5. move-assignment operator - not yet coded
    //   6. swap - not yet coded
    ~ImageMatrix();

    int get_height() const {
        return height;
    }
    int get_width() const {
        return width;
    }
    double& at(int const row, int const col) {
        check(row, col);
        return data[row][col];
    }
    double const& at(int const row, int const col) const {
        check(row, col);
        return data[row][col];
    }
private:
    void check(int const row, int const col) const {
        if (row < 0 || height <= row)
            throw std::out_of_range("ERROR: row is out of range.");
        if (col < 0 || width <= col)
            throw std::out_of_range("ERROR: col is out of range.");
    }
};

// The constructors of the ImageMatrix class
// Constructor currently in use
ImageMatrix::ImageMatrix(int height, int width, double value)
    : height(height), width(width)
{
    //this->height = height;  // redundant
    //this->width = width;    // redundant

    if (height <= 0)
        throw std::invalid_argument("ERROR: height is zero.");
    if (width <= 0)
        throw std::invalid_argument("ERROR: width is zero.");

    // This could throw std::bad_alloc.
    data = new double* [height];

    // Each call to `new` in the loop below could throw.
    // If any one of them does, then you must back out 
    // (i.e., delete) all of the allocations that were 
    // successful.
    //
    // If there is a throw, then variable `i` will hold the 
    // subscript that was not allocated. All subscripts less 
    // than `i` must have their allocations deleted.
    //
    // In addition, after a throw, you must deallocate the 
    // memory assigned to pointer `data`.
    // 
    // Those deallocations happen in the catch block.

    int i{};
    try {
        for (; i < height; ++i) {
            data[i] = new double[width];
        }
    }
    catch (std::bad_alloc const&) {
        while (i--)
            delete[] data[i];
        delete[] data;
        throw;
    }

    // Initialize
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; j++) {
            data[i][j] = value;
        }
    }
}

// Destructor
ImageMatrix::~ImageMatrix() {
    if (data) {
        for (int i{ height }; i--;) {
            delete[] data[i];
        }
        delete[] data;
        data = nullptr;
    }
}

void display(ImageMatrix const& m)
{
    for (int row{}; row < m.get_height(); ++row) {
        for (int col{}; col < m.get_width(); ++col) {
            std::cout << std::setw(12) << m.at(row, col);
        }
        std::cout.put('\n');
    }
    std::cout.put('\n');
}
void test(
    std::string_view heading,
    int const rows,
    int const cols,
    double const value)
{
    ImageMatrix m{ rows, cols, value };
    std::cout << std::format(
        "{}"
        "\n"
        "\n  height: {}, width: {}"
        "\n  value: {}"
        "\n\n"
        , heading
        , m.get_height()
        , m.get_width()
        , value
    );
    display(m);
}
export int main()
{
    test("Example 1", 1, 1, 0);
    test("Example 2", 1, 1, 1.1);
    test("Example 3", 2, 2, 1);
    test("Example 4", 2, 2, 2.2);
    test("Example 5", 3, 3, 0);
    test("Example 6", 3, 3, 3.3);
    return 0;
}
// end file: main.ixx

这是输出:

Example 1

  height: 1, width: 1
  value: 0

           0

Example 2

  height: 1, width: 1
  value: 1.1

         1.1

Example 3

  height: 2, width: 2
  value: 1

           1           1
           1           1

Example 4

  height: 2, width: 2
  value: 2.2

         2.2         2.2
         2.2         2.2

Example 5

  height: 3, width: 3
  value: 0

           0           0           0
           0           0           0
           0           0           0

Example 6

  height: 3, width: 3
  value: 3.3

         3.3         3.3         3.3
         3.3         3.3         3.3
         3.3         3.3         3.3

为什么要重新发明轮子?

这是另一种可能的解决方案。我只是半开玩笑地提出这个!

// ImageMatrix.h
#ifndef IMAGEMATRIX_H
#define IMAGEMATRIX_H

// Class Array2D by @PaulMacKenzie
// https://godbolt.org/z/4zsoqnb11
#include "Array2D.h"

using ImageMatrix = Array2D<double>;

// end file: ImageMatrix.h
© www.soinside.com 2019 - 2024. All rights reserved.