簡體   English   中英

c ++對象正在創建同一數組的兩個實例,但是作用域不同?

[英]c++ Object is creating two instances of the same array, but in different scopes?

我在我的一個班上遇到了問題。 該類中只有1個array <>成員。 我正在構建此類的靜態對象,並在函數中初始化值。 問題是永遠不會插入值。

當我進入調試器並查看該數組中的一些基本插入語句時,該數組仍為空。 但是,如果我進入插入函數本身,則會看到一個完全相同名稱的“第二”數組,並按預期存儲值。

在我看來,好像有一個靜態的外部作用域數組,其中沒有任何內容,還有另一個內部版本(完全相同的數組),其內容已正確存儲。

我在這里缺少什么嗎? 我真的不知道為什么會這樣。

這是根據要求的最小源代碼

circularbuffer.hpp

#ifndef __ma__circularbuffer_guard
#define __ma__circularbuffer_guard


#include <array>

template < typename T, int SIZE> 
class CircularBuffer
{
private:
int _index;
int _size;
std::array<T, SIZE> _buffer;
public:
CircularBuffer() { _index = 0; _size = SIZE; }

int             length  ();
typename T&     at      (int);
void            insert  (T);
int             index   ();

private:
int     realign (int&);


};

template < typename T, int SIZE> 
int CircularBuffer<T, SIZE>::realign (int& index)
{
if (index >= _size)
{
    index -= _size;
    realign(index);
} else if (index < 0)
{
    index += _size;
    realign(index);
}
return index;
}


template < typename T, int SIZE> 
int CircularBuffer<T, SIZE>::length ()
{
return _size;
}


template < typename T, int SIZE> 
typename T& CircularBuffer<T, SIZE>::at (int index)
{
realign(index);
return _buffer.at(index);
}


template <typename T, int SIZE>
void CircularBuffer<T, SIZE>::insert (T data)
{
realign(_index);
_buffer.at(_index) = data;
_index += 1;
}


template <typename T, int SIZE>
int CircularBuffer<T, SIZE>::index ()
{
return _index;
}

#endif

全局緩沖區初始化

#ifndef __guard__namespace__notes__
#define __guard__namespace__notes__

#include "circularbuffer.hpp"
#include <memory>

typedef CircularBuffer<char, 7> CB_Natural_T;
typedef CircularBuffer<int, 12> CB_Chromatic_T;

static CB_Natural_T WHITENOTES = CB_Natural_T();        // buffer of letter notes
static CB_Chromatic_T POSITIONS = CB_Chromatic_T();     // buffer of absolute positions on keyboard

struct Initialize
{
    Initialize()
    {
        WHITENOTES.insert('C');
        WHITENOTES.insert('D');
        WHITENOTES.insert('E');
        WHITENOTES.insert('F');
        WHITENOTES.insert('G');
        WHITENOTES.insert('A');
        WHITENOTES.insert('B');

        // Initialize all positions
        for (int i = 0; i < 12; ++i)
            POSITIONS.insert(i);
    }
};

static Initialize dummy_init_var = Initialize();

#endif

初始化靜態緩沖區,以便可以對其他類進行單元測試。

注意類頭和cpp

#ifndef __guard__note__
#define __guard__note__


#include "macros.h"
#include <string>
#include <memory>


class Note
{
public:
enum Qualities { UNKNOWN = -3, DFLAT, FLAT, NATURAL, SHARP, DSHARP };   // qualities of note
typedef DEF_PTR(Note);                                                  // pointer type
private:
char _letter [1];       // the letter of the note
std::string _name;      // the full name of the note    
int _value;             // absolute value
int _position;          // relative position
Qualities _quality;     // sharp/natural/flat quality

public:
Note();
Note(char);             // letter
Note(char, Qualities);  // letter, and quality

// setters
void sharp();       // Sets the quality of the note to 1
void Dsharp();      // Sets the quality of the note to 2
void flat();        // Sets the quality of the note to -1
void Dflat();       // Sets the quality of the note to -2
void natural();     // Sets the quality of the note to 0

// getters
char letter() const;        /* returns character letter */
std::string name() const;   /* returns true name of note */
int position() const;       /* returns relative position on keyboard */
int quality() const;        /* returns the quality of the note */
void respell() const;       /* respells a note to the nearest other note */

static pointer_type make(char);             // returns a shared pointer of a new Note
static pointer_type make(char, Qualities);  // returns a shared pointer of a new Note

// operators
bool operator ==(Note& r) const;    // Returns true if Notes are truly equal
bool operator !=(Note& r) const;    // Returns true if Notes are truly not equal

bool isEnharmonic(Note& r) const;   // Returns true if Notes are enharmonically equal
bool isNatural() const;             // Returns true if Note is natural
bool isSharp() const;               // Returns true if Note is sharp
bool isDSharp() const;              // Returns true if Note is double sharp
bool isFlat() const;                // Returns true if Note is flat
bool isDFlat() const;               // Returns true if Note is double flat

private:
void makeName();    /* sets name of Note */
};


#endif


#include "note.h"

Note::Note() 
{
_letter[1] = 'u';
_name = ""; 
_value = -1; 
_quality = UNKNOWN;
_position = -1;
}

Note::Note(char l)
{
_letter[1] = l;

// determine absolute value based on letter
switch (l)
{
case 'C':
    _value = 0; break;
case 'D':
    _value = 2; break;
case 'E':
    _value = 4; break;
case 'F':
    _value = 5; break;
case 'G':
    _value = 7; break;
case 'A':
    _value = 9; break;
case 'B':
    _value = 11; break;
default:
    _value = -1; break;
}

_quality = NATURAL;
_position = _value + _quality;
makeName();
}

Note::Note(char l, Note::Qualities q)
{
_letter[1] = l;

// determine absolute value based on letter given
switch (l)
{
case 'C':
    _value = 0; break;
case 'D':
    _value = 2; break;
case 'E':
    _value = 4; break;
case 'F':
    _value = 5; break;
case 'G':
    _value = 7; break;
case 'A':
    _value = 9; break;
case 'B':
    _value = 11; break;
default:
    _value = -1; break;
}

_quality = q;       // assert for good data
_position = _value + _quality;
makeName();
}

void Note::sharp()      { _quality = SHARP;     _position = _value + 1; makeName();}
void Note::Dsharp()     { _quality = DSHARP;    _position = _value + 2; makeName();}
void Note::flat()       { _quality = FLAT;      _position = _value - 1; makeName();}
void Note::Dflat()      { _quality = DFLAT;     _position = _value - 2; makeName();}
void Note::natural()    { _quality = NATURAL;   _position = _value;     makeName(); }

char Note::letter() const       { return _letter[1]; }
std::string Note::name() const  { return _name; }
int Note::position() const      { return _position; }
int Note::quality () const      { return _quality; }


Note::pointer_type Note::make(char l)                    { return pointer_type(new Note(l)); }
Note::pointer_type Note::make(char l, Note::Qualities q) { return pointer_type(new Note(l, q)); }

void Note::makeName()
{
_name = "";
_name += _letter[1];    // add letter to name

// find out quality, add quality to name
switch (_quality)
{
case DFLAT:
    _name += "bb"; break;
case FLAT:
    _name += "b"; break;
case SHARP:
    _name += "#"; break;
case DSHARP:
    _name += "x"; break;
case NATURAL:
    break;
default:
    _name += "u"; break;
}
}

bool Note::operator ==(Note& r) const
{
// true if letter, value, position, and quality are all equal
return (_letter[1] == r._letter[1]) && (_value == r._value) && (_position == r._position) && (_quality == r._quality);
}

bool Note::operator !=(Note& r) const
{
return !(*this == r);
}

bool Note::isEnharmonic (Note& r) const
{
return (_position == r._position);
}

bool Note::isNatural() const
{
return _quality == NATURAL;
}

bool Note::isSharp() const
{
return _quality == SHARP;
}

bool Note::isDSharp() const
{
return _quality == DSHARP;
}

bool Note::isFlat() const
{
return _quality == FLAT;
}

bool Note::isDFlat() const
{
return _quality == DFLAT;
}

我也會發布間隔,但是那個間隔很大。 但是基本上在Intervals函數之一中有這段代碼叫做findInterval

區間:: findInterval

void Interval::findInterval(Note& bottom, Note& top)
{
int index = 0;      // temp placeholder for start position

// find where the bottom note is in relation to buffer
for (int i = 0; i < WHITENOTES.length(); ++i)
{
    if (bottom.letter() == WHITENOTES.at(i))
    {
        index = i;  // set start position to this position
        break;
    }
}

// find the interpreted interval
// starting from index, with offset of length + index
for (int i = index; i < (index + WHITENOTES.length()); ++i)
{
    if (top.letter() == WHITENOTES.at(i))
    {
        _interval = i - index;  // set interval
        break;
    }
}

// modify index to serve as the position of the bottom note
index = bottom.position();

// find the physical distance
for (int i = index; i < (index + POSITIONS.length()); ++i)
{
    if (top.position() == POSITIONS.at(i))      // values match
    {
        _distance = i - index;                  // set physical distance
        break;
    }
    else if (top.position() > 11 && ((top.position() - 11) == POSITIONS.at(i)))     // if top position is higher than octave
    {
        _distance = (i - index) + 11;
        break;
    }
}


}

它無法在此處設置數據成員,因為WHITENOTES為空,即使我調用了使用靜態結構對其進行初始化也是如此。

需要注意的另一件事是,如果我編譯ut_interval,所有測試都可以完美返回而沒有失敗,並且當我在調試器中檢查緩沖區的值時,它們顯示為\\ 0。 但是它仍然會通過if語句,並將char與字母匹配(這是調試器中對char的某種加密嗎?)

但是,ut_chord中的#include完全相同,因此無法評估間隔

這是間隔ut和和弦ut的示例

ut_interval

#include "../common/namespace_notes.h"
#include "../common/note.h"
#include "../common/interval.h"

#define BOOST_TEST_MODULE IntervalTest
#include <boost/test/auto_unit_test.hpp>



#define TEST_IVL(i, dist, itv, q, n) \
BOOST_CHECK(i.distance() == dist); \
BOOST_CHECK(i.interval() == i.itv); \
BOOST_CHECK(i.quality() == i.q); \
BOOST_CHECK(i.name() == n)



BOOST_AUTO_TEST_CASE(INTERVAL_UNISONS)
{
// make some notes
Note C = Note('C');
Note Cs = Note('C', Cs.SHARP);
Note Cds = Note('C', Cds.DSHARP);
Note Cf = Note('C', Cf.FLAT);
Note Cdf = Note('C', Cdf.DFLAT);

// make some intervals
Interval PUnison = Interval(C, C);
Interval AugUnison = Interval(C, Cs);
Interval Aug2Unison = Interval(C, Cds);
Interval DimUnison = Interval(C, Cf);
Interval Dim2Unison = Interval(C, Cdf);

// make sure members are accurate
TEST_IVL(PUnison, 0, UNISON, PER, "Perfect Unison");
BOOST_CHECK(PUnison.isPerfect());

TEST_IVL(AugUnison, 1, UNISON, AUG, "Augmented Unison");
BOOST_CHECK(AugUnison.isAugmented());

TEST_IVL(Aug2Unison, 2, UNISON, AUG, "Augmented Unison");
BOOST_CHECK(AugUnison.isAugmented());

TEST_IVL(DimUnison, 1, UNISON, AUG, "Augmented Unison");
BOOST_CHECK(DimUnison.isAugmented());

TEST_IVL(Dim2Unison, 2, UNISON, AUG, "Augmented Unison");
BOOST_CHECK(Dim2Unison.isAugmented());
}

ut_chord

#include "../common/namespace_notes.h"
#include "../common/note.h"
#include "../common/interval.h"
#include "../common/chord.h"

#define BOOST_TEST_MODULE ChordTest
#include <boost/test/auto_unit_test.hpp>
#include <memory>


BOOST_AUTO_TEST_CASE(ChordConstructor)
{
typedef std::shared_ptr<Note> nt;
nt C = nt(new Note('C'));
nt E = nt(new Note('E'));
nt G = nt(new Note('G'));
nt B = nt(new Note('B'));

Interval PUnison = Interval(*C, *C); // cannot determine this interval
Chord C7 = Chord(C , E, G, B);
Chord C72 = Chord(B, G, E, C);
Chord C73 = Chord(E, G, C, B);
}

首先,您不應包含.cpp文件。 要解決鏈接器問題,請遵循包含模型 :將函數定義放在模板的頭文件中。

其次,我嘗試了以下示例程序,並且現在可以正常工作-該問題可能是由於鏈接器錯誤引起的。

閱讀該SO問題 ,以獲取有關包括cpp文件(和模板)的更多信息。

main.cpp中:

#include <array>
#include "circularbuffer.h"


typedef CircularBuffer<char, 7> CB_Natural_T;
typedef CircularBuffer<int, 12> CB_Chromatic_T;

static CB_Natural_T WHITENOTES = CB_Natural_T();        // buffer of letter notes
static CB_Chromatic_T POSITIONS = CB_Chromatic_T(); 

int main()
{   
    WHITENOTES.insert('C');
    WHITENOTES.insert('D');
    WHITENOTES.insert('E');
    WHITENOTES.insert('F');
    WHITENOTES.insert('G');
    WHITENOTES.insert('A');
    WHITENOTES.insert('B');

    // Initialize all positions
    for (int i = 0; i < 12; ++i)
        POSITIONS.insert(i);

    return 0;
}

circularbuffer.h:

#ifndef _CIRCULAR_BUFFER_H
#define _CIRCULAR_BUFFER_H

#include <array>

template < class T, int SIZE> 
class CircularBuffer
{
private:
    int _index;
    int _size;
    std::array<T, SIZE> _buffer;
public:
    CircularBuffer() : _index(0), _size(SIZE), _buffer() {}

    int length ()
    {
        return _size;
    }

    T& at (int index)
    {
        realign(index);
        return _buffer.at(index);
    }

    void insert (T data)
    {
        realign(_index);
        _buffer.at(_index) = data;
        _index += 1;
    }
    int index ()
    {
        return _index;
    }
private:
    int realign (int& index)
    {
        if (index >= _size)
        {
            index -= _size;
            realign(index);
        } else if (index < 0)
        {
            index += _size;
            realign(index);
        }
        return index;
    }
};

#endif

另外,使用包含保護措施以確保文件不被包含兩次。

static CB_Natural_T WHITENOTES = CB_Natural_T();
static CB_Chromatic_T POSITIONS = CB_Chromatic_T();

正是這兩個行為不符合您的預期,對嗎? 由於這些是全局變量,因此您應該放

extern CB_Natural_T WHITENOTES;
extern CB_Chromatic_T POSITIONS;

進入頭文件以聲明它們,

CB_Natural_T WHITENOTES;
CB_Chromatic_T POSITIONS;

到一個cpp文件中以實際定義它們。 static導致這些對象具有內部鏈接,因此每個包含標頭的文件(精確地:編譯單元)都將創建兩個這樣的對象,而不是在不同文件之間共享它們。

我也認為這兩個對象是常量,對嗎? 在這種情況下,您可以這樣聲明它們。 然后,您將需要一個生成這些對象的助手或一個允許初始化的構造函數:

CB_Natural_T whitenotes()
{
    CB_Natural_T init;
    ...
    return init;
}
CB_Natural_T const WHITENOTES = whitenotes();

筆記:

  • 如上所述,“ = T()”是多余的。
  • 模板SIZE參數存儲在一個int中,這是不必要的,因為該值始終存在。
  • 您正在使用realign()函數,該函數既修改參數又返回結果。 我只會使用其中之一。 另外,由於它是僅修改參數而不接觸任何成員的函數(請參見上文!),因此可以將其設為靜態函數。 至少它應該是const成員函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM