首页 > 解决方案 > 应用程序因包含静态变量的类的全局对象声明而崩溃

问题描述

我有一个包含一些静态变量的类 Texture,这些变量可以用作查找表。这些将用于计算 GLCM(灰度并发矩阵)属性。它们保持静态,因为一旦生成,它们可以在同一类的不同对象之间共享,而与创建的对象数量无关。这是我的班级标题。

纹理.h

#pragma once
#ifndef TEXTURE_H
#define TEXTURE_H

#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <algorithm>
#include <string>

class Texture
{
public:
    Texture();
    ~Texture();

private:

    const static int MAXIMUM_GLCM = 4; //!< Maximum number of GLCM matrices that would be computed (same as num of directions)

    const static int MAX_LEVELS = 256; //!< Maximum number of levels is assumed to be 256. A valid assumption for 8-bit gray-scale images.

    static cv::Mat lutWeights; //! @brief LUT to generate Contrast, Dissimilarity, Similarity and Homogeneity weights.
    static cv::Mat contrastWeights; //! @brief Container for Contrast and Homogeneity weights.
    static cv::Mat dissimilarWeights; //! @brief Container for Dissimilarity and Similarity weights.

    /*!
     * Generates a 256-element single channel LUT of of type CV_32F. The elements start from 0 and
     * increase linearly.
     * @param[in] None
     * @param[in] None
     * @param[out] None
     */
    static void generateLUT();

    /*!
     * Populates required weight matrices based on the LUT generates as part of generateLUT().
     * The generated weight matrices are single channel and of type CV_32F
     * @param[in] None
     * @param[in] None
     * @param[out] None
     */
    static void prepareWeightMatrices();
};
#endif // !TEXTURE_H

以下是我的texture.cpp文件。

#include "texture.h"
using namespace std;
using namespace cv; //!< /namespace for OpenCV

cv::Mat Texture::lutWeights = cv::Mat::zeros(cv::Size2i(Texture::MAX_LEVELS,1), CV_32FC1); //! @brief Intialise static LUT with zeros.
cv::Mat Texture::contrastWeights = cv::Mat::zeros(cv::Size2i(Texture::MAX_LEVELS, Texture::MAX_LEVELS), CV_32FC1); //! @brief Intialise static Contrast weights with zeros.
cv::Mat Texture::dissimilarWeights = cv::Mat::zeros(cv::Size2i(Texture::MAX_LEVELS, Texture::MAX_LEVELS), CV_32FC1); //! @brief Intialise static Dissimilarity weights with zeros.

void Texture::generateLUT()
{
    cout << "\ngenerateLUT()";
    for (int i = 0; i < lutWeights.cols; i++)
    {
        lutWeights.at<float>(i) = (float)i; //! Every index is an entry for the LUT.
    }
}

void Texture::prepareWeightMatrices()
{
    cout << "\nprepareWeightMatrices()";
    generateLUT(); //! Generate LUT

    int rowSpan = dissimilarWeights.rows - 1;
    cout << "\n rowSpan: " << rowSpan;
    for (int i = 0; i < rowSpan; i++)
    {
        lutWeights.colRange(1, (rowSpan +1) - i).copyTo(dissimilarWeights.row(i).colRange(i+1, rowSpan +1));
    }

    cv::completeSymm(dissimilarWeights, false); //! Mirror the upper triangle.
    cv::accumulateSquare(dissimilarWeights, contrastWeights); //! Elementwise square to generate contrast weights.
}

Texture::Texture()
{
    prepareWeightMatrices(); //! Generate weights matrices
}

Texture::~Texture()
{
}

现在,问题是如果我声明一个类的全局对象,我的应用程序就会崩溃。见下面我的main.cpp

#include "texture.h"
using namespace std;

Texture texture;
int main()
{
    return(0);
}

但是,在工作中声明对象main()没有任何问题。

#include "texture.h"
using namespace std;

int main()
{
    Texture texture;
    return(0);
}

崩溃的调试显示,在全局声明的情况下,权重矩阵 'lutWeights'、'contrastWeights' 和 'dissimilarWeights' 没有被初始化,并且由于变为 -1 而在函数中发生cv::completeSymm(dissimilarWeights, false)崩溃。但是,通过本地声明,初始化似乎正在发生并且具有正确的值255prepareWeightMatrices()rowSpanrowSpan

所以,问题是,

  1. 为什么在全局声明对象时不会发生初始化?
  2. 如何使用全局对象声明复制局部对象声明的行为?
  3. 从设计的角度来看,即使这个问题得到了解决,我应该继续这个类定义还是重新评估我的决定?

我仍在探索类的静态成员函数和变量。提前致谢。

标签: c++11static-initialization

解决方案


基本问题是未定义不同编译单元中全局静态变量的初始化顺序(在编译单元中,它们按顺序初始化)-因此在您的情况下, main.cpp 中的全局静态变量在那些之前被初始化在 texture.cpp 中。也没有办法“设置”订单,它只是实现定义的。您可以依赖的唯一全局顺序是,没有构造函数的类型的默认初始化静态变量将在任何实际需要构造函数调用的全局变量之前进行零初始化。

所以你有几个选择

  • 所有全局静态定义放入一个编译单元(按您想要的顺序)
  • 仔细编码您的构造函数,以便它们不依赖于正在初始化的静态变量。在这里,零初始化会有所帮助——您可以创建全局静态变量指针,并确保任何想要使用它们的人检查它们是否为 nullptr(如果是则初始化它们)。

推荐阅读