为什么std :: cout会改变我的变量?

时间:2017-02-16 19:49:46

标签: c++ io c++14 std stdout

我以为自己疯了,但我的堆分配值在传递给cout <<时被修改。

为了概括地描述我的设置,我有一个环形缓冲区,其中包含基本上(valuetimestamp)元组的类(doubledouble)类型。我正在尝试实现一个信号延迟,使得传递到此缓冲区的值在最终发出之前保持在缓冲区中一段固定的延迟。我已经用一些已知的初始条件初始化了这些对象的缓冲区大小1024,然后在收到新的输入值时,我查看列表的头部,看看它的时间戳和新值的时间戳之间的差异是否大于延迟。如果是,我将列表的头部弹出并丢弃它。最后,我返回列表的当前头部。

这一切都与我期望的一样。

如果我添加一个简单的print语句(在我的main中,在调用延迟过滤器之后):

std::cout << "Signal out of delay filter: (" << s.get << ", " << s.get_timestamp() << ").\n";

但是,一切都爆炸了。突然,我的环形缓冲区中的元素充满了垃圾数据,这打破了我的时间戳比较。

有什么想法吗?这里有一些可能相关的代码片段,我可以根据要求发布更多内容。

编辑:我在缓冲区的第一个条目上设置了一个观察点,以查看它的修改位置,它肯定在cout <<调用中。以下是GDB所说的话

Hardware watchpoint 2: d.buf.buffer[0]  

Old value = {value = 0, timestamp = 0} 
New value = {value = 4.10047448604823463e-322, timestamp = 0}
_IO_new_file_overflow (f=0x7ffff783a620 <_IO_2_1_stdout_>, ch=83) at fileops.c:857 857:        
fileops.c: No such file or directory

编辑2 :我不确定如何正确附加MVCE,但这是文件的内容。我希望这是最小的,但它捕获了问题所以它至少是一个CVE。如果这太多了,我可以尝试进一步减少它,但如果它变得更小,我冒着消除bug的风险:

的CMakeLists.txt:

# Project Definiton

cmake_minimum_required(VERSION 3.5)
project("ring_buffer_mvce")

set_property(GLOBAL PROPERTY CXX_STANDARD 14)
set_property(GLOBAL PROPERTY CXX_STANDARD_REQUIRED ON)

# Automated Unit Test Configuration
enable_testing()

add_executable(delay_test
  src/signals/delay.cpp
  src/test/delay_test.cpp)

add_test(delay_test delay_test)

的src /信号/ delay.cpp

#include "delay.hpp"

delay::delay(double time, size_t buffer_size, signal<double> initial_condition) {
    this->time = time;
    buf = ring_buffer<signal<double> >(buffer_size);
    for (int i = 0; i < buffer_size; i++) {
        buf.push(initial_condition);
    }
}

delay::~delay() {
}

signal<double> delay::apply(signal<double> s) {
    // Add the current signal to the delay buffer
    buf.push(s);

    // Check to see if our current time has elapsed
    double cur_time_delta = s.get_timestamp() - buf.peek().get_timestamp();
    if (cur_time_delta >= (time - DELAY_EPSILON)) {
        buf.pop();
    }

    return buf.peek();
}

的src /信号/ delay.hpp:

#ifndef __DELAY_H__
#define __DELAY_H__

#include <cstddef>
#include <limits>
#include "signal.hpp"
#include "filter.hpp"
#include "../utils.h"

#define DELAY_EPSILON 0.00001

class delay : public filter<double> {
    public:
    delay(double time, size_t buffer_size, signal<double> initial_condition);
    ~delay();

    virtual signal<double> apply(const signal<double>);

    private:
    double time;
    ring_buffer<signal<double> > buf;
};

#endif

的src /信号/ filter.hpp:

#ifndef __FILTER_HPP__
#define __FILTER_HPP__

#include "signal.hpp"

template <class t>
class filter {
    public:
    virtual signal<t> apply(const signal<t>) = 0;
};

#endif

的src /信号/ signal.hpp:

#ifndef __SIGNAL_HPP__
#define __SIGNAL_HPP__

#include <algorithm>

template <class t>
class signal {
    public:
    signal<t>(t value, double timestamp);

    signal<t>();

    t get();
    double get_timestamp();

    private:
    t value;
    double timestamp;
};


template <class t>
signal<t>::signal(t value, double timestamp) {
    this->value = value;
    this->timestamp = timestamp;
}

template <class t>
signal<t>::signal() {
    timestamp = -1;
}

template <class t>
double signal<t>::get_timestamp() {
    return timestamp;
}


template <class t>
t signal<t>::get() {
    return value;
}

#endif

的src / utils.h:

#ifndef __UTILS_H__
#define __UTILS_H__

#include <cstring>

template <class t>
class ring_buffer {
    public:

    ring_buffer(size_t buffer_size);
    ring_buffer();
    ~ring_buffer();
    void push(t data);
    t peek();
    t pop();

    private:
    t* buffer;
    int data_start_idx;
    int data_end_idx;
    size_t size;
};

template <class t>
ring_buffer<t>::ring_buffer(size_t buffer_size) {
    buffer = new t[buffer_size];
    size = buffer_size;
    data_start_idx = 0;
    data_end_idx = 0;
}

template <class t>
ring_buffer<t>::ring_buffer() {
    ring_buffer(64);
}

template <class t>
ring_buffer<t>::~ring_buffer() {
    delete[] buffer;
}

template <class t>
t ring_buffer<t>::peek() {
    return buffer[data_start_idx];
}

template <class t>
t ring_buffer<t>::pop() {
    t data = buffer[data_start_idx];
    data_start_idx = (data_start_idx + 1) % size;
    return data;
}

template <class t>
void ring_buffer<t>::push(t data) {
    buffer[data_end_idx] = data;
    data_end_idx = (data_end_idx + 1) % size;
}

#endif

的src /测试/ delay_test.cpp:

#include <iostream>
#include <stdio.h>
#include "../signals/signal.hpp"
#include "../signals/filter.hpp"
#include "../signals/delay.hpp"

int main(int argc, char **argv) {
    delay d = delay(0.5, 1024, signal<double>(0, 0));

    double sig = 0;
    double t = 0;
    signal<double> s = signal<double>(0, 0);
    while (true) {
        s = d.apply(signal<double>(sig, t));
        std::cout << "Signal out of delay filter: (" << s.get() << ", " << s.get_timestamp() << ").\n";

        sig += 1;
        t += 0.1;

        getchar();
    }

    return 0;
}

1 个答案:

答案 0 :(得分:0)

当你得到这样奇怪的效果时,由于某些内存管理错误,总是意味着某种内存损坏。

在valgrind下运行delay_test会产生数千错误:

==28617== Invalid write of size 8
==28617==    at 0x400EED: ring_buffer<signal<double> >::push(signal<double>) (in /tmp/sig/delay_test)
==28617==    by 0x400C10: delay::delay(double, unsigned long, signal<double>) (in /tmp/sig/delay_test)
==28617==    by 0x401065: main (in /tmp/sig/delay_test)
==28617==  Address 0x5ab40c0 is 0 bytes inside a block of size 16,384 free'd
==28617==    at 0x4C2D6FA: operator delete[](void*) (vg_replace_malloc.c:621)
==28617==    by 0x400E04: ring_buffer<signal<double> >::~ring_buffer() (in /tmp/sig/delay_test)
==28617==    by 0x400BDC: delay::delay(double, unsigned long, signal<double>) (in /tmp/sig/delay_test)
==28617==    by 0x401065: main (in /tmp/sig/delay_test)
==28617==  Block was alloc'd at
==28617==    at 0x4C2C8F9: operator new[](unsigned long) (vg_replace_malloc.c:423)
==28617==    by 0x400E3E: ring_buffer<signal<double> >::ring_buffer(unsigned long) (in /tmp/sig/delay_test)
==28617==    by 0x400BB4: delay::delay(double, unsigned long, signal<double>) (in /tmp/sig/delay_test)
==28617==    by 0x401065: main (in /tmp/sig/delay_test)
==28617== 
...
...
==28617== HEAP SUMMARY:
==28617==     in use at exit: 0 bytes in 0 blocks
==28617==   total heap usage: 5 allocs, 5 frees, 92,160 bytes allocated
==28617== 
==28617== All heap blocks were freed -- no leaks are possible
==28617== 
==28617== For counts of detected and suppressed errors, rerun with: -v
==28617== ERROR SUMMARY: 2060 errors from 8 contexts (suppressed: 0 from 0)

在内存被释放后,你正在从内存中读取和写入,即更改的内存位置不是你的变量,它们在内存中已被解除分配,然后重新分配给其他内容。

您的ring_buffer管理动态分配的内存,但没有用户定义的复制构造函数或赋值运算符。这意味着它完全被打破了。