2017-02-16 6 views
-2

私は狂ったと思ったが、ヒープ割り当て値はcout <<に渡されている間に変更されている。一般的に私のセットアップを記述するためにstd :: coutが自分の変数を変更するのはなぜですか?

が、私は基本的なクラスを含むリングバッファを持っている(valueは、timestamp)(doubledouble)とのタプルを入力します。私は、このバッファに渡された値が最終的に放出される前にある固定遅延のためにバッファに保持されるような信号遅延を実装しようとしています。私はいくつかの既知の初期条件でこれらのオブジェクトのバッファーサイズ1024を初期化してから、新しい入力値を受け取った時点で、リストの先頭でそのタイムスタンプと新しい値のタイムスタンプの差が遅延より大きいかどうかを調べます。そうであれば、私はリストの先頭をポップして破棄します。最後に、私はリストの現在の頭部を返します。

これはすべて、私が期待しているとおりに動作します。

私は(遅延フィルタを呼び出した後、私のメインで)簡単なprint文を追加する場合:

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だから問題を取り込んでいます。これが多すぎると、私はさらにそれを削減しようとすることができますが、私はそれをはるかに最小限取得する場合は、バグを排除するリスクを実行します。

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 /シグナル/遅延。 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; 
} 
+0

実際にタイミングはありません。スレッディングなどはありません。私はすべてが離散タイムステップで実行されるように信号をシミュレートしています。私はそれが間違いなく変更されていることを知っています** ** cout << 'GDBウォッチポイント経由で、私は私のポストに正確な場所を追加します。 –

+2

明らかに間違ったことはありません。 'cout'は渡した引数を変更しません。おそらくあなたの 'get'関数や' operator << 'に副作用がありますか? –

+0

私のget関数は、基本的な1行のアクセサメソッドではありません(上記で編集しました)。私は演算子<<があるかどうかわからない。 –

答えて

0

それ常には、いくつかのメモリ管理バグによるメモリ破壊のいくつかの種類を意味します。変更されたメモリ位置があなたの変数ではありません。すなわち、彼らはしている、

==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) 

それが割り当て解除されていた後、あなたはメモリからの読み出しと書いている:valgrindの下にdelay_testを実行

何千ものエラーのを生成します割り当て解除されたメモリは、別のもののために再割り当てされます。

ring_bufferは、動的に割り当てられたメモリを管理しますが、ユーザー定義のコピーコンストラクタまたは割り当て演算子はありません。それは完全に壊れていることを意味します。

+0

ねえ、これです。 ring_bufferに必要なコピーコンストラクタを定義し、期待通りに機能するようになりました。私はC++のオブジェクトインスタンス化の手順についていくつか読んでいるように見えます。ありがとう! –

関連する問題