Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.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++;班级变动什么*这";指_C++_Class_Vector_This_Variable Assignment - Fatal编程技术网

C++ C++;班级变动什么*这";指

C++ C++;班级变动什么*这";指,c++,class,vector,this,variable-assignment,C++,Class,Vector,This,Variable Assignment,我有一个类“foo”,它包含一个成员向量,其中包含类型为“foo”的元素。这个类有一个名为“make”的方法,它创建“foo”对象并将它们附加到向量。我还提供了一种导航“foo”对象的方法,它的“foo”向量元素称为“get” 我想重新分配任何“foo”对象上的“this”所指内容,以指向其向量中的一个foo对象。我想为代码提供这个功能,作为一种更有效地导航和跟踪foo对象的方法,而不必将引用绑定到特定的“foo”成员。我试图通过一个名为“setAsNode”的方法来实现这一点,该方法重新分配“

我有一个类“foo”,它包含一个成员向量,其中包含类型为“foo”的元素。这个类有一个名为“make”的方法,它创建“foo”对象并将它们附加到向量。我还提供了一种导航“foo”对象的方法,它的“foo”向量元素称为“get”

我想重新分配任何“foo”对象上的“this”所指内容,以指向其向量中的一个foo对象。我想为代码提供这个功能,作为一种更有效地导航和跟踪foo对象的方法,而不必将引用绑定到特定的“foo”成员。我试图通过一个名为“setAsNode”的方法来实现这一点,该方法重新分配“*this”是什么

下面是我模拟的一些示例代码,我相信这些代码能让我的观点得到理解:

struct foo{
    foo(const std::string &r):s(r){}
    foo& make(const std::string &r){children.push_back(test(r)); children.back().originalNode = originalNode; return children.back();}
    foo& setAsNode(){*originalNode = *this; return *originalNode;}
    foo& get(int i){return children.at(i);}
private:
    std::vector<foo> children;
    std::string s = "someData";
    foo *originalNode = this;
};
我意识到我可能正在实施一些非常糟糕的编程实践,例如使用引用而不是指针来返回“foo”对象,但我真的不知道如何正确地构造这样的程序,或者该程序的最佳实践版本看起来/工作起来如何。无论是谁,只要能向我展示“正确”的做事方式,都可以获得额外积分


回到真正的问题上来:我如何让类似的东西,特别是“setAsNode”方法,真正起作用?还有,为什么我的示例中的代码不起作用?注意,它编译得很好,只是在运行时崩溃了

在您的示例中,调用
foo.get(0).get(0).setAsNode()
将尝试将
foo.get(0).get(0)
的值复制到
foo
。在此过程中,
foo.children
将被分配一个新值,导致向量清除其先前的元素,从而导致
foo.get(0).get(0)
的销毁。这意味着
已被销毁,指针无法使用。但是,这是在分配操作期间发生的,我们目前正在使用
this
。要解决此问题,必须确保要复制的值持续足够长的时间才能被复制。直观的解决方案可能是在赋值之前复制要赋值的值

foo& setAsNode() { 
    auto this_copy = *this;
    *originalNode = std::move(this_copy); 
    return *originalNode; 
}
这将起作用,但在分配给
*originalNode
后,您仍必须小心不要使用
。另一个解决方案是在执行赋值之前控制
原始节点的子向量。在此版本中,
在方法返回之前保持有效,但如果以下赋值引发异常,则树将处于无效状态

foo& setAsNode() { 
    auto original_vect = std::move(originalNode->children);
    *originalNode = *this;
    return *originalNode; 
}
总而言之,我会对一个要求物体自杀的设计持谨慎态度。它意味着对象控制自己的所有权或所有权责任是循环的。< / P> < P> C++模式(并且可以说是唯一正确的方式)是分离关注点。< /P> foo不是(或不应该)foo查找器。它应该做foo的事情,而不是foo导航的事情

创建一个新类作为foo的游标或迭代器

这里是一个稍微扩展的版本,其中foo_光标会记住它在foo堆栈中的旅程。对于您的问题来说,这可能有点过头了,但它展示了将foo导航逻辑与foo实现逻辑分离的原理

这样做的越多,程序的编写、调试和维护就越容易

#include <utility>
#include <string>
#include <vector>
#include <stack>
#include <stdexcept>
#include <iostream>


struct foo{
    foo(const std::string &r)
        : children()
        , s(r)
    {}

    foo& make(const std::string &r)
    {
        children.emplace_back(r);
        return children.back();
    }

    foo& get(int i)
    {
        return children.at(i);
    }

    void print() const {
        std::cout << s << std::endl;
    }


private:

    std::vector<foo> children;
    std::string s = "someData";
};

struct foo_cursor
{
    foo_cursor(foo& f)
        : current_(std::addressof(f))
    {}

    foo_cursor& down(int i)
    {
        history_.push(current_);
        current_ = std::addressof(current_->get(i));
        return *this;
    }

    foo_cursor& up() {
        if (history_.empty()) {
            throw std::logic_error("went up too far");
        }
        else {
            current_ = history_.top();
            history_.pop();
        }
        return *this;
    }

    foo* operator->() const {
        return current_;
    }

private:
    foo* current_;
    std::stack<foo*> history_;
};


int main()
{
    foo f("a");
    f.make("b").make("c");

    auto fc = foo_cursor(f);
    fc.down(0).down(0)->print();
    fc.up()->print();
    fc.up()->print();
}

如果改用
std::unique_ptr
容器,则可以确保每个
T
的地址不变。仅移动
唯一的\u ptr
。或者,您可能需要考虑使用容器具有更有利的引用失效策略。例如,
std::list
仅当相关元素从列表中删除时才使引用无效。要直接回答标题中的问题,无法使
指向另一个实例。充其量,您可以调用另一个实例的方法,其中
this
将不同于先前上下文中的
this
。我不理解您为什么需要您声称需要的东西。如果删除
originalNode
setAsNode
内容,则示例中的几乎所有内容都可以正常工作。为了了解您真正需要的内容:只编写
f1=f1.get(0).get(0)有什么问题
@R.MartinhoFernandes这正是我试图捕获的功能,但即使尝试运行您建议的代码也会导致崩溃。另外,从技术上讲,我并不“需要”我声称我需要的东西,我只是在试验代码,看看我能完成什么,提出了这个思想实验,并想知道它为什么会这样,以及是否有一个正确的方法来开始。
#include <utility>
#include <string>
#include <vector>
#include <stack>
#include <stdexcept>
#include <iostream>


struct foo{
    foo(const std::string &r)
        : children()
        , s(r)
    {}

    foo& make(const std::string &r)
    {
        children.emplace_back(r);
        return children.back();
    }

    foo& get(int i)
    {
        return children.at(i);
    }

    void print() const {
        std::cout << s << std::endl;
    }


private:

    std::vector<foo> children;
    std::string s = "someData";
};

struct foo_cursor
{
    foo_cursor(foo& f)
        : current_(std::addressof(f))
    {}

    foo_cursor& down(int i)
    {
        history_.push(current_);
        current_ = std::addressof(current_->get(i));
        return *this;
    }

    foo_cursor& up() {
        if (history_.empty()) {
            throw std::logic_error("went up too far");
        }
        else {
            current_ = history_.top();
            history_.pop();
        }
        return *this;
    }

    foo* operator->() const {
        return current_;
    }

private:
    foo* current_;
    std::stack<foo*> history_;
};


int main()
{
    foo f("a");
    f.make("b").make("c");

    auto fc = foo_cursor(f);
    fc.down(0).down(0)->print();
    fc.up()->print();
    fc.up()->print();
}
c
b
a