我正在实现类似模板矢量的类。我希望我的向量在int
和Product
类上运行,该类在main中定义。它适用于int
,但Product
类Valgrind报告以下内容:
==22629== Memcheck, a memory error detector
==22629== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22629== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==22629== Command: ./a.out
==22629== v2 = ==22629== Invalid read of size 1
==22629== at 0x4C30F62: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22629== by 0x4018DF: Product (main.cpp:33)
==22629== by 0x4018DF: my_vector (my_vector.h:24)
==22629== by 0x4018DF: void test_my_vector<Product>(Product, Product) (main.cpp:100)
==22629== by 0x400E67: main (main.cpp:175)
==22629== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==22629==
==22629==
==22629== Process terminating with default action of signal 11 (SIGSEGV)
==22629== Access not within mapped region at address 0x0
==22629== at 0x4C30F62: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22629== by 0x4018DF: Product (main.cpp:33)
==22629== by 0x4018DF: my_vector (my_vector.h:24)
==22629== by 0x4018DF: void test_my_vector<Product>(Product, Product) (main.cpp:100)
==22629== by 0x400E67: main (main.cpp:175)
==22629== If you believe this happened as a result of a stack
==22629== overflow in your program's main thread (unlikely but
==22629== possible), you can try to increase the size of the
==22629== main thread stack using the --main-stacksize= flag.
==22629== The main thread stack size used in this run was 8388608.
好吧,似乎我将NULL传递给了strlen,但是由于我传递了NULL并且我没有任何Product
构造函数,这些构造函数用name_
填充NULL
字段,它意味着我已经删除了对象,它正被传递给复制构造函数。至少这些是我的想法。
但我真的不明白我的错误在哪里。也许是因为placement new
或其他一些内存管理错误的使用不当。
我还有test_my_vector
函数,用于测试我的矢量。
的main.cpp
#include <iostream>
#include <fstream>
#include <cstring>
#include <assert.h>
#include "my_vector.h"
using namespace std;
class Product {
public:
Product(const char* name, int quantity, double price){
name_ = new char[strlen(name) + 1];
strcpy(name_, name);
quantity_ = quantity;
price_ = price;
}
Product(){
name_ = new char[strlen("") + 1];
strcpy(name_, "");
quantity_ = 0;
price_ = 0;
}
~Product(){
delete [] name_;
}
Product(const Product& other){
price_ = other.price_;
quantity_ = other.quantity_;
name_ = new char[strlen(other.name_) + 1];
strcpy(name_, other.name_);
};
const Product& operator=(const Product& other){
delete [] name_;
price_ = other.price_;
quantity_ = other.quantity_;
name_ = new char[strlen(other.name_) + 1];
strcpy(name_, other.name_);
return other;
};
private:
char* name_;
int quantity_;
double price_;
};
template <typename T>
void test_my_vector(T t1, T t2){
//some asserts
}
int main() {
test_my_vector<int>(5, 10);
test_my_vector<Product>(Product("asdf", 4, 12.0), Product("qwe", -1, 7.5));
return 0;
}
和my_vector.h
template <class T>
class my_vector{
public:
my_vector(){
capacity_ = 0;
size_ = 0;
array_ = NULL;
};
my_vector(const size_t n){
size_ = n;
capacity_ = (size_t) pow(2, ceil(log(n)/log(2)));
array_ = (T*)(new char[sizeof(T) * capacity_]());
};
my_vector(const my_vector<T>& other){
size_ = other.size_;
capacity_ = other.capacity_;
array_ = (T*)(new char[sizeof(T) * capacity_]);
for(size_t i = 0; i < size_; i++)
new (&array_[i]) T(other.array_[i]), std::cout << i;
};
my_vector<T>& operator=(const my_vector<T>& other){
this -> ~my_vector();
size_ = other.size_;
capacity_ = other.capacity_;
array_ = (T*)(new char[sizeof(T) * capacity_]);
for(size_t i = 0; i < size_; i++)
new (&array_[i]) T(other.array_[i]);;
return *this;
};
~my_vector(){
for(size_t i = 0; i < size_; i++)
array_[i].~T();
delete [] (char*) array_;
};
void resize(const size_t n){
reserve(n);
size_ = n;
};
void reserve(const size_t n){
if (n > capacity_){
if(!capacity_) capacity_ = 1;
while(capacity_ < n)
capacity_ *= 2;
T* new_array = (T*)(new char[sizeof(T) * capacity_]);
for (size_t i = 0; i < size_; i++)
new (&new_array[i]) T(array_[i]);;
this -> ~my_vector();
array_ = new_array;
}
};
void push_back(const T& t){
if (!capacity_)
reserve(2);
else if(size_ == capacity_)
reserve(2 * capacity_);
new (&array_[size_]) T(t);
size_++;
};
private:
size_t capacity_;
size_t size_;
T* array_;
};
答案 0 :(得分:0)
第一个错误:您的my_vector
构造函数不会创建对象。它所做的就是初始化对象的内存,但不构造它们。最后发生的事情是随后的复制操作正在使用无效对象。
更正如下:
my_vector(const size_t n)
{
size_ = n;
capacity_ = (size_t)pow(2, ceil(log(n) / log(2)));
array_ = (T*)(new char[sizeof(T) * capacity_]());
for (size_t i = 0; i < size_; i++)
new (&array_[i]) T(); // default construct objects
};
此外,如果您要使用整数指数,我建议不要使用pow
。评论中的链接plus this one显示了使用pow
进行整数计算时会发生什么。
第二个错误:您的赋值运算符不正确,因为它们不检查自我赋值。保存所有这些麻烦并使用copy / swap idiom作为您的赋值运算符:
#include <algorithm>
//...
Product& operator=(const Product& other)
{
Product temp(other);
std::swap(temp.name_, name_);
std::swap(temp.price, price);
std::swap(temp.quantity_, quantity_);
return *this;
}
使用my_vector
可以完成同样的事情:
my_vector<T>& operator=(const my_vector<T>& other)
{
my_vector<T> temp(other);
std::swap(temp.size_, size_);
std::swap(temp.capacity_, capacity_);
std::swap(temp.array_, array_);
return *this;
}