【发布时间】:2020-02-03 15:22:55
【问题描述】:
我一直在尝试将用户定义的类型(或类)与 C++ 标准库容器 - 向量一起使用。我希望能够使用内置的 C++ 类型、int、float、string 等的向量来做我喜欢做的通常的事情。但是使用我自己定义的类型。我编写了一个使用box 类的小示例程序来尝试了解发生了什么。
这是该类的代码:
class box {
private:
float *lengthPtr;
std::string *widthPtr;
public:
box(float a, std::string b) {
std::cout<<"Constructor called" << '\n';
lengthPtr = new float;
*lengthPtr = a;
widthPtr = new std::string;
*widthPtr = b;
}
// copy constructor
box(const box &obj){
std::cout<< "User defined copy constructor called" << '\n';
lengthPtr = new float;
*lengthPtr = obj.check_length();
widthPtr = new std::string;
*widthPtr = obj.check_width();
}
// copy assignment operator
box& operator=(const box &that) {
std::cout<< "Copy assignment operator called";
float *localLen = new float;
*localLen = that.check_length();
delete[] lengthPtr;
lengthPtr = localLen;
std::string *localWid = new std::string;
*localWid = that.check_width();
delete[] widthPtr;
widthPtr = localWid;
return *this;
}
~box() {
std::cout << "User defined destructor called." << '\n';
delete lengthPtr;
delete widthPtr;
}
float check_length () const {
return *lengthPtr;
}
std::string check_width() const{
return *widthPtr;
}
void set_legnth(const float len) {
*lengthPtr = len;
}
void set_width(const std::string str) {
*widthPtr = str;
}
void print_box_info(){
std::cout << *lengthPtr << " " << *widthPtr << '\n';
}
};
我希望能够做的两件事主要是:
使用
.push_back()将任意数量的我的用户定义类型 (box) 的新元素添加到向量中。存储元素后,我想使用
std::sort和用户定义的比较函数对它们进行排序。
这是我用来测试我的两个目标的主要功能:
int main() {
srand(time(NULL));
int i = 0;
std::vector<box> boxes;
while (i<25) {
int x = rand()%100+1;
std::cout<< "x = " << x << '\n';
if ( i < 5)
boxes.push_back(box(x, "name"));
if ( i > 4 && i < 12)
boxes.push_back(box(x, "Agg"));
if ( i > 11 && i < 20 )
boxes.push_back(box(x, "Cragg"));
if (i>19)
boxes.push_back(box(x, "Lagg"));
std::cout << "Added the new box to the collection." << '\n';
i++;
}
for(unsigned int j = 0; j<boxes.size(); j++) {
boxes[j].print_box_info();
}
std::sort(boxes.begin(), boxes.end(), type_is_less);
}
到目前为止,我编写的代码似乎能够完成目标 1。运行程序后,while 循环之后的 for 循环打印存储在我的框向量中的 25 个框的信息。但是,当我尝试使用 std::sort 和 type_is_less() 函数对我的盒子进行排序时:
bool type_is_less(const box &a, const box &b) {
std::cout<<"In type is less." << '\n';
std::string A = a.check_width();
std::string B = b.check_width();
std::cout<< "Comparing box a, width = " << A << '\n';
std::cout<< "with box b, width = " << B << '\n';
bool val = A<B;
std::cout << "Returning " << val <<'\n' <<'\n';
return A<B;
}
我遇到了分段错误,但我不确定错误来自何处。用户定义的复制构造函数似乎是 seg 故障发生之前调用的最终函数。在push_back() 中似乎可以使用复制构造函数,但在std::sort 中会导致问题?
我尝试在每行之间使用std::cout 消息调试复制构造函数,并且复制构造函数的每一行似乎都在执行时不会导致段错误。一旦复制构造函数完成执行,seg 错误似乎就会出现。我的控制台输出的尾部在下面(//我使用'//'插入了cmets):
将新盒子添加到集合中。
3 个名字
//...
//...
// 程序打印每个框的 2 个信息点
61 Lagg // 这是最终的盒子信息打印。
输入类型较少。 比较框 a,宽度 = 名称 带框 b,宽度 = Cragg 返回 0
输入类型较少。 比较框 a,宽度 = 名称 带框 b,宽度 = Lagg 返回 0
输入类型较少。 比较框 a,宽度 = Cragg 带框 b,宽度 = Lagg 返回 1
调用用户定义的拷贝构造函数
分段错误(核心转储)
这里有一些移动部件,我不确定如何找出我的代码的哪一部分行为不正确。一切似乎都指向用户定义的复制构造函数是罪魁祸首,但我不确定如何调整它。任何建议将不胜感激。
我尚未调查的一个悬而未决的问题是,我是否可以定义一个与此类似的类,但使用非指针变量lengthPtr 和widthPtr,并且仍然具有相同的功能。
【问题讨论】:
-
您的复制赋值运算符不防范自赋值。修复它,看看您的问题是否仍然存在。
-
如果你传递给
delete []一些你没有从new []得到的东西,行为是不确定的。 -
使用复制/swap:
box& operator=(const box &that) { box temp(that); std::swap(widthPtr, temp.widthPtr); std::swap(lengthPtr, temp.lengthPtr); return *this; } -
复制/交换修复它的原因是因为它绕过了您在尝试重新创建副本时所犯的所有错误。比如错误使用
delete[]而不是delete,不检查自赋值等问题。如果您有一个正常工作的、非错误的复制构造函数和析构函数,那么在赋值运算符中使用它们。 See this -
我宁愿(在这种情况下)只是将成员声明为对象。如果要使用指针,请考虑使用 std::unique_ptr 或 std::shared_ptr。