函数返回时,带指针的复制构造函数失败



我是这里的新用户,这是我的第一个问题,所以请不要苛刻地评判我。我不仅在这个网站上,而且在其他网站上也检查了许多类似的问题。但我没有找到答案。

问题是使用指针创建复制构造函数。对于那些可能会问:为什么需要指针?的人:我有一个类stmt,其中包含vector<stmt>,它将允许我构造树状数据结构。然后,我将执行一些函数来更改 stmt 参数的值。没有指针,它们不会改变

它编译,但随后给出异常未处理(运行时错误(

我的第一个尝试看起来像这样:

struct stmt
{
string lexeme;
int *size;
int *lay;
bool *nl;
vector<stmt>* follow;
stmt(string l)
{
lexeme = l;
size = new int;
*size = l.size()+2;
lay = new int;
*lay = 0;
nl = new bool;
*nl = false;
follow = new vector<stmt>;
}
stmt(const stmt &s)
{
lexeme = s.lexeme;      
size = new int;         //Crashes here : Unhandled exception:std::length_error at memory location ... 
*size = *s.size;
lay = new int;
nl = new bool;
follow = new vector<stmt>;
follow = s.follow;
}
};

第二次我也尝试了这个:

stmt(const stmt &s)
:lexeme.(s.lexeme), size (s.size), ......and so on
{}

不幸的是,这也无济于事。

所以,这是我的第三次尝试,但没有帮助

重要提示:我注意到当我尝试使用返回类型为stmt的函数在另一个stmt的向量中创建和emplace_back新的stmt元素时,就会发生这种情况。

下面是一个表示关键问题的代码:

stmt Program("Program");
stmt ParseRelop(string  p);
void EMP(stmt s)
{
s.follow->push_back(ParseRelop("token"));
}
stmt ParseRelop(string  p)
{
stmt s(p);
return s;
}
int main()
{
EMP(Program);
cout<<Program.follow->at(0).lexeme;
}

像这样

stmt(const stmt &s)
{
...
follow = new vector<stmt>(*s.follow);
}

此版本通过从复制的对象复制向量来分配新向(*s.follow是复制对象中的向量(。

您的版本分配了一个新指针,但随后用复制对象的指针副本覆盖了它。

您要复制矢量,而不是指向矢量的指针。

您应该对其他指针使用相同的技术

size = new int(*s.size);
lay = new int(*s.lay);

等。

让我们首先使您的stmt类副本正确。 一旦你这样做了,那么问题将来自代码的其他部分,这些部分不涉及stmt泄漏内存或访问无效内存:

#include <vector>
#include <string>
#include <algorithm>
struct stmt
{
std::string lexeme;
int *size;
int *lay;
bool *nl;
std::vector<stmt>* follow;
// Constructor.  Note the usage of the member initialization list
stmt(std::string l) : lexeme(l), size(new int), lay(new int(0)), nl(new bool(false)),
follow(new std::vector<stmt>())
{
*size = l.size() + 2;
}
// Copy constructor.  Note that we use the member initialization list, 
// and copy all the members from s to the current object, not partial copies
stmt(const stmt &s) : lexeme(s.lexeme), size(new int(*s.size)), nl(new bool(*s.nl)),
lay(new int(*s.lay)), follow(new std::vector<stmt>(*s.follow))
{}
// The assignment operator.  Note that we use copy / swap to swap out
// all the members, and that a check for self-assignment is done.
stmt& operator=(const stmt &s)
{
if (this != &s)
{
stmt temp(s);
std::swap(lexeme, temp.lexeme);
std::swap(size, temp.size);
std::swap(lay, temp.lay);
std::swap(nl, temp.nl);
std::swap(follow, temp.follow);
}
return *this;
}
// The destructor destroys all the memory 
~stmt()
{
delete size;
delete lay;
delete nl;
delete follow;
}
};

这个类现在正确地遵循了 3 的规则,并且应该是可安全复制的。 我在注释中输入了每个函数的作用,您应该研究为什么该类现在应该正常工作。

我不想深入太多,因为实际上你不会有指向intbool甚至vector<stmt>的指针。

引用:

法则 3

复制/交换成语

最新更新