无法确定未初始化值的来源

Trouble pinpointing source of uninitialized value

我正在为 BeagleBone Green 编写一个简单的地震检测程序,使用我连接的振动传感器,以及一个带有内置加速度计和数字显示器的斗篷。地震探测器的大脑位于EarthquakeDetector class.

earthquake_detector.h:

#pragma once
#include <atomic>
#include <thread>

#include <Accelerometer/accelerometer.h>
#include <DigitDisplay/digit_display.h>
#include <VibrationSensor/vibration_sensor.h>

namespace earthquake_detection_unit {

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

private:
    // Worker thread for continuous earthquake monitoring.
    void Worker();

    // Monitors accelerometer readings. This function returns after a certain 
    // number of consecutive low readings.
    void AccelerometerMonitor();

    // Displays current magnitude on the digit display.
    void DisplayMagnitude();

    // Worker thread member variable.
    std::thread worker_thread;
    // Signal to shutdown worker thread.
    std::atomic<bool> shutdown;

    // Pointers to devices.
    Accelerometer *accelerometer;
    DigitDisplay *digit_display;
    VibrationSensor *vibration_sensor;
};

} // earthquake_detection_unit

earthquake_detector.cc:

#include <iostream>

#include "earthquake_detector.h"

namespace earthquake_detection_unit {

const double kScaleValue1Threshold = 0.144;
const double kScaleValue2Threshold = 0.281;
const double kScaleValue3Threshold = 0.418;
const double kScaleValue4Threshold = 0.555;
const double kScaleValue5Threshold = 0.692;
const double kScaleValue6Threshold = 0.829;
const double kScaleValue7Threshold = 0.966;
const double kScaleValue8Threshold = 1.103;
const double kScaleValue9Threshold = 1.24;

const int kAccelerometerTimeoutTotal_ms = 10000;
const int kAccelerometerSamplePeriod_ms = 100;
const int kAccelerometerTimeoutNumPeriods = kAccelerometerTimeoutTotal_ms / kAccelerometerSamplePeriod_ms;

EarthquakeDetector::EarthquakeDetector() : shutdown(false) {
    // Initialize digit display.
    digit_display = new DigitDisplay();

    worker_thread = std::thread(&EarthquakeDetector::Worker, this);
}

EarthquakeDetector::~EarthquakeDetector() {
    shutdown.store(true, std::memory_order_relaxed);
    worker_thread.join();

    // Shutdown digit display.
    delete digit_display;
}

void EarthquakeDetector::Worker() {
    while (!shutdown) {
        std::cout << "\t<EarthquakeDetector> ";
        std::cout << "Launching vibration sensor to listen for a vibration." << std::endl;
        // First, wait for a vibration.
        vibration_sensor = new VibrationSensor();
        vibration_sensor->WaitForVibration();
        delete vibration_sensor;

        // After detecting a vibration, launch accelerometer.
        std::cout << "\t<EarthquakeDetector> ";
        std::cout << "Vibration detected -- vibration sensor shutdown, launching accelerometer." << std::endl;
        accelerometer = new Accelerometer();

        // Monitor accelerometer readings.
        AccelerometerMonitor();

        // Flash magnitude.
        digit_display->FlashDisplay();
        // Reset digit display to display 0.
        digit_display->SetDigit(0);

        // Shutdown accelerometer for lack of activity.
        std::cout << "\t<EarthquakeDetector> ";
        std::cout << "Shutting down accelerometer due to inactivity." << std::endl;
        delete accelerometer;
    }
}

void EarthquakeDetector::AccelerometerMonitor() {
    // This function returns if we obtain kAccelerometerTimeoutNumPeriods
    // consecutive low readings from the accelerometer.
    int consecutive_readings = 0;
    while (consecutive_readings != kAccelerometerTimeoutNumPeriods) {
        DisplayMagnitude();
        if (accelerometer->GetCurrentReading() >= kScaleValue1Threshold) {
            consecutive_readings = 0;
        }
        else {
            ++consecutive_readings;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(kAccelerometerSamplePeriod_ms));
    }
}

void EarthquakeDetector::DisplayMagnitude() {
    double acc_reading = accelerometer->GetHighestReading();

    unsigned int digit_to_display = 0;
    if (acc_reading >= kScaleValue9Threshold) {
        digit_to_display = 9;
    }
    else if (acc_reading >= kScaleValue8Threshold) {
        digit_to_display = 8;
    }
    else if (acc_reading >= kScaleValue7Threshold) {
        digit_to_display = 7;
    }
    else if (acc_reading >= kScaleValue6Threshold) {
        digit_to_display = 6;
    }
    else if (acc_reading >= kScaleValue5Threshold) {
        digit_to_display = 5;
    }
    else if (acc_reading >= kScaleValue4Threshold) {
        digit_to_display = 4;
    }
    else if (acc_reading >= kScaleValue3Threshold) {
        digit_to_display = 3;
    }
    else if (acc_reading >= kScaleValue2Threshold) {
        digit_to_display = 2;
    }
    else if (acc_reading >= kScaleValue1Threshold) {
        digit_to_display = 1;
    }

    digit_display->SetDigit(digit_to_display);
}

} // earthquake_detection_unit

问题: Valgrind 抱怨一个未初始化的 unsigned int(我使用了 --track-origins=yes 选项)并且我找不到我可能有一个未初始化值的地方我的实施。我多次收到以下错误,大概是因为在执行代码时,它落入了 DisplayMagnitude.

中的 if 语句行
==1023== Thread 2:
==1023== Conditional jump or move depends on uninitialised value(s)
==1023==    at 0x10A2DA: earthquake_detection_unit::EarthquakeDetector::DisplayMagnitude() (earthquake_detector.cc:85)
==1023==    by 0x10A227: earthquake_detection_unit::EarthquakeDetector::AccelerometerMonitor() (earthquake_detector.cc:70)
==1023==    by 0x10A15B: earthquake_detection_unit::EarthquakeDetector::Worker() (earthquake_detector.cc:51)
==1023==    by 0x10B705: void std::__invoke_impl<void, void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(std::__invoke_memfun_deref, void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:73)
==1023==    by 0x10B633: std::__invoke_result<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>::type std::__invoke<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:95)
==1023==    by 0x10B5A1: void std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::_M_invoke<0u, 1u>(std::_Index_tuple<0u, 1u>) (thread:244)
==1023==    by 0x10B53F: std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::operator()() (thread:251)
==1023==    by 0x10B515: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> > >::_M_run() (thread:195)
==1023==    by 0x48FAA69: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.22)
==1023==  Uninitialised value was created by a heap allocation
==1023==    at 0x4840194: operator new(unsigned int) (vg_replace_malloc.c:415)
==1023==    by 0x10A147: earthquake_detection_unit::EarthquakeDetector::Worker() (earthquake_detector.cc:48)
==1023==    by 0x10B705: void std::__invoke_impl<void, void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(std::__invoke_memfun_deref, void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:73)
==1023==    by 0x10B633: std::__invoke_result<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>::type std::__invoke<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:95)
==1023==    by 0x10B5A1: void std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::_M_invoke<0u, 1u>(std::_Index_tuple<0u, 1u>) (thread:244)
==1023==    by 0x10B53F: std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::operator()() (thread:251)
==1023==    by 0x10B515: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> > >::_M_run() (thread:195)
==1023==    by 0x48FAA69: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.22)

我想知道是否有人可以指出可能导致这些错误的正确方向。我看过关于类似问题的各种 SO 帖子,但似乎没有什么真正适用于我的情况。谢谢!

编辑 1: 加速度计接口的简化版本。我删掉了很多 I2C 文件读写的部分,让这篇文章尽可能简洁。

accelerometer.h:

namespace earthquake_detection_unit {

class Accelerometer {
public:
    typedef struct Vector {
        Vector(int16_t x_reading, int16_t y_reading, int16_t z_reading);

        double x;
        double y;
        double z;
        double magnitude;
    } Vector;

    Accelerometer();
    ~Accelerometer();

    inline double GetCurrentReading() { return current_reading; }
    inline double GetHighestReading() { return highest_reading; }

private:
    // Worker thread for sampling accelerometer readings.
    void Worker();

    void CollectReading();

    void ActivateAccelerometer();
    void ShutDownAccelerometer();

    // Signal to shutdown worker thread.
    std::atomic<bool> shutdown;
    // Worker thread.
    std::thread worker_thread;
    // Exponentially smoothed accelerometer magnitude reading.
    std::atomic<double> current_reading;
    // Highest reading detected by accelerometer.
    std::atomic<double> highest_reading;
};

} // earthquake_detection_unit

accelerometer.cc:

namespace earthquake_detection_unit {

Accelerometer::Accelerometer() {
    std::atomic<bool> shutdown(false);
    std::atomic<double> current_reading(0.0f);
    std::atomic<double> highest_reading(0.0f);

    // Activate accelerometer using I2C.
    ActivateAccelerometer();

    worker_thread = std::thread(&Accelerometer::Worker, this);
}

Accelerometer::~Accelerometer() {
    shutdown = true;
    worker_thread.join();
    // Shut down accelerometer via I2C.
    ShutDownAccelerometer();
}

Accelerometer::Vector::Vector(int16_t x_reading, int16_t y_reading, int16_t z_reading) {
    // Omitted: constructs Vector object containing accelerations and magnitude.
}

void Accelerometer::Worker() {
    while (!shutdown) {
        CollectReading();
        if (current_reading > highest_reading) {
            highest_reading.store(current_reading, std::memory_order_relaxed);
        }

        // Gather samples every 2 ms.
        std::this_thread::sleep_for(std::chrono::milliseconds(kSleepTime_ms));
    }
}

void Accelerometer::CollectReading() {
    // Omitted: collect accelerometer sample and store it in
    //          latest_vector_reading.
    Vector latest_vector_reading(x_reading, y_reading, z_reading);

    double latest_magnitude_reading = latest_vector_reading.magnitude;

    current_reading.store(kSmoothingFactor * latest_magnitude_reading +
                          (1.0f - kSmoothingFactor) * current_reading,
                          std::memory_order_relaxed);
}

} // earthquake_detection_unit

除非我弄错了你的问题是你的构造函数

Accelerometer::Accelerometer() {
    std::atomic<bool> shutdown(false);
    std::atomic<double> current_reading(0.0f);
    std::atomic<double> highest_reading(0.0f);

    // Activate accelerometer using I2C.
    ActivateAccelerometer();

    worker_thread = std::thread(&Accelerometer::Worker, this);
}

上面的highest_reading是一个局部变量,隐藏了class范围内的同名变量。您正在初始化此局部变量并使 class 成员未初始化。

试试

Accelerometer::Accelerometer() : shutdown(false), current_reading(0.0), highest_reading(0.0) {
    // Activate accelerometer using I2C.
    ActivateAccelerometer();

    worker_thread = std::thread(&Accelerometer::Worker, this);
}

我正在使用初始化列表,这通常是初始化 class 成员的首选方式。