Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当函数返回时,带指针的复制构造函数失败_C++_Visual C++ - Fatal编程技术网

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

C++ 当函数返回时,带指针的复制构造函数失败,c++,visual-c++,C++,Visual C++,我是这里的新用户,这是我的第一个问题,所以请不要对我太苛刻。我检查了许多类似的问题,不仅在这个网站上,也在其他网站上。但我没有找到答案 问题是使用指针创建复制构造函数。对于那些可能会问:为什么需要指针?:我有一个类stmt,它包含vector,它允许我构造树状数据结构。然后我将执行一些函数来更改stmt参数的值。没有指针,它们不会改变 它编译,但随后给出异常未处理的运行时错误 我的第一次尝试如下所示: struct stmt { string lexeme; int *size;

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

问题是使用指针创建复制构造函数。对于那些可能会问:为什么需要指针?:我有一个类stmt,它包含vector,它允许我构造树状数据结构。然后我将执行一些函数来更改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的函数在另一个stmt的向量中创建并放置新的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);
}

等等。

让我们从修改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,并且应该可以安全地复制。我在注释中说明了每个函数的作用,您应该研究一下为什么该类现在应该正常工作

我不想太深入,因为实际上你不会有指向int、bool甚至vector的指针

参考资料:


你必须使用指针吗?前面的实践将为您提供一个可以由隐式生成的复制构造函数复制的类型。所有指向的成员都具有值语义。避免使用原始指针,而是使用智能指针或直接使用值或容器。它可以编译,但是-它编译只意味着您编写了语法有效的内容-编译器理解您的指令。这对于你的代码是正确的还是没有bug几乎毫无意义。@JesperJuhl他们可能知道这一点,因为他们在这里请求帮助解决这个问题。知道问题是运行时错误是我们希望他们告诉我们的有价值的信息;我们不要因为这件事责骂他们。@Asteroid我不是想责骂他们。只是说一个很多人都忽略的事实。似乎很有帮助,但我对其他的建议也有问题:我留下了一条评论。我能用*号做什么,你能帮忙吗?对不起,没用。至少谢谢你的邀请answer@TattimbetZakariya上面的代码是在复制构造函数中复制指针的正确方法。如果你的代码仍然不工作,那么你可能还有其他的bug。我知道,我也检查了其他类似的问题,这就是为什么我还附上了一个函数使用示例。请检查一下!我能用*号做什么?将其声明为int,而不是int*。对基元类型使用指针没有意义。lay和nl也一样。事实上,这里根本没有理由使用指针。我复制了您编写的代码,但问题仍然存在。谢谢你的尝试和建议。请你检查一下问题正文底部的一个非常清晰和简短的例子,它显示了我的确切错误案例,并告诉我你对此有何看法?你的错误与我发布的代码完全无关。它与您在这里使用一个临时变量有关:void empsmt s。但是,我发布的答案修复了该调用的一个问题,而且复制stmt对象现在是安全的,即使在传递值时使用了错误的stmt对象。不,这不是毫无意义的-它指出了按值传递对象的缺陷,并期望结果反映回调用方。如果您现在更改为作废empsmt&s;这个小例子现在可以毫无问题地工作了。我认为你是第一个正确处理这个问题的人。你知道怎么修吗?我会很感激的!如果希望看到调用方中反映的结果,请确保函数将引用作为参数。EMP的一个错误——确保你在实际的程序中没有犯同样的错误。除此之外,stmt类本身不再是一个问题。
    size = new int(*s.size);
    lay = new int(*s.lay);
#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;
    }
};