コードには多くの問題があったので、どこから始めるべきかを知ることは難しいです。 :)
私はジョン・バーガーが言ったことに同意する。
私はあなたのコードを私のPCにアップロードして毎回それをアップロードするのをやめ、それにvalgrindを使うことができました。確かにあなたがベクトルを印刷した後、valgrindはエラーを報告しました。その理由は簡単です。クラスのコピーを print_vec
に渡しました。つまり、 print_vec
の終了時にデストラクタが呼び出され、メモリの割り当てが解除されました。あなたはコピーコンストラクタを持っていたはずです。それがなければ、コンパイラはクラスのビット単位のコピーを作成します。つまり、割り当てられた同じメモリを共有する2つのオブジェクトがあります。
迅速かつ厄介な修正は、 print_vec
を参照して呼び出すことです。
void print_vec(vector & v){
しかし、これは未来のためにバグを潜んでいる。
下の例ではコピーコンストラクタを実装しましたが、参照によって print_vec
を呼び出すと、コピーするクラスが保存され、実行中の new/delete
メモリの断片化を軽減する可能性があります。
John Burgerは次のように述べています。デストラクタをあなた自身に呼んではいけません!そうすることはできません。デストラクタと clear
関数で同じことをしたい場合は、 clear()
を呼び出すデストラクタを取得してください。
The use of leading double-underscores in variables is contrary to the C++ Standard. Don't do that. Use a trailing underscore if you want to indicate a member variable. Lose all the this->
references. They just clutter things up.
配列を割り当てるので、 delete []
を使うべきです。
なぜこれを行うのですか?これは不要な割り当てです。
vector i = vector();
ちょうど:
vector i;
何らかの理由でクラスを割り当てる場合は、 operator =
も実装する必要があります。そうしないと、コピーコンストラクタの場合と同じ問題が発生します。 (私の例を見てください)。
ここでは、関数を呼び出さずに関数(容量とサイズ)をテストします。
bool isempty() {
return !this->__data ||
!this->capacity ||
!this->size;
}
あなたは本当にこれを行うことはできません:
T const & operator[] (unsigned int idx) const {
if (idx < this->__count) {
return this->__data[idx];
}
else {
//throw exception or handle error to be implemented
}
}
"else"パスを指定すると、関数は値を返しません(警告をオンにすると、コンパイラの警告が表示されます)。
私の修正された例、その中に私の提案があります。それは警告やエラーなしでコンパイルされ、クラッシュすることなく実行されます(PC上)。
// g++ -std=c++11 -g3 test.cpp -o test
// OR: clang -std=c++11 -g3 -Wall test.cpp -lstdc++ -o test
//
// valgrind --leak-check=yes ./test
#include //printf
#include /* memcpy */
#define min(a,b) (a < b) ? a : b
template
class vector {
public:
//empty constructor
vector() : capacity_(0), count_(0), data_(nullptr) {}
//copy constructor
vector (const vector & rhs) : capacity_(0), count_(0), data_(nullptr)
{
data_ = new T [rhs.capacity_];
capacity_ = rhs.capacity_;
count_ = rhs.count_;
memcpy (data_, rhs.data_, sizeof (T) * count_);
} //end of copy constructor
//operator=
vector & operator= (const vector & rhs)
{
//gracefully handle self-assignment (eg. a = a;)
if (this == &rhs )
return *this;
data_ = new T [rhs.capacity_];
capacity_ = rhs.capacity_;
count_ = rhs.count_;
memcpy (data_, rhs.data_, sizeof (T) * count_);
return *this;
} //end of operator=
//destructor
~vector()
{
clear ();
} //end of destructor
T const & operator[] (unsigned int idx) const {
return data_[idx];
}
T& operator[] (unsigned int idx) {
return data_[idx];
}
void resize_to_fit() {
resize(count_);
}
T& pop_back(){
return data_[--count_];
}
void push_back(T obj)
{
if (capacity_ == count_) {
resize(capacity_ + 1);
}
data_[count_++] = obj;
}
bool isempty() {
return count_ == 0;
}
void clear() {
delete [] data_;
data_ = nullptr;
count_ = capacity_ = 0;
}
T* data() {
return data_;
}
int size() {
return count_;
}
int capacity() {
return capacity_;
}
private:
void resize(int capacity) {
if (data_ == nullptr) {
data_ = new T[capacity];
count_ = 0;
capacity_ = capacity;
}
else if (capacity > capacity_) { //else do nothing
//allocate new memory
T* data = new T[capacity];
//count can't be higher than capacity
count_ = min(count_, capacity);
capacity_ = capacity;
//copy data across to new pointer
memcpy(data, data_, sizeof(T) * count_);
//delete old pointer
delete [] data_;
//now remember the new pointer
data_ = data;
}
}
protected:
int capacity_;
int count_;
T* data_;
};
void print_vec(vector v){
printf("%s\n", "Printing new vec!");
for( int i = 0; i < v.size(); i++){
printf("%i\n", v[i]);
}
}
int main() {
vector i;
i.push_back(10);
i.push_back(2);
print_vec(i);
i.push_back(3);
vector j;
//test assignment
j = i;
print_vec(j);
print_vec(i);
while(i.size() > 0){
print_vec(i);
i.pop_back();
}
}