C++类更改"*this"所指的内容

C++ class changing what "*this" refers to

本文关键字:C++ this      更新时间:2023-10-16

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

我想重新分配任何" this"在任何" foo"对象上指向其向量中的foo对象上的" this"。我想将代码此功能作为一种更有效地导航并跟踪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 f1("test1");
f1.make("test2").make("test3");//pushes a new foo element back to the vector in f1 and pushes a new foo element back to it's vector
f1.get(0).get(0);//refers to the deepest nested object we just made above, cumbersome to type especially if the nesting is deep
f1.get(0).get(0).setAsNode();//this is where the error occurs, the desired effect is to make f1 the same object as denoted by f1.get(0).get(0);
foo& f2 = f1.get(0).get(0);//f2 would be equivalent to what I want the above code to reset f1 to be (or at least how I'd like it to act)

我意识到我可能正在实施一些非常糟糕的编程实践,例如使用参考,而不是用于返回" foo"对象的指针,但老实说,我不知道如何正确构建这样的程序,或者如何最佳实践该程序的版本看起来/工作。任何人都可以向我展示"正确"做事方式的奖励积分。

回到真正的问题:我将如何做这样的事情,特别是" setAsnode"方法,实际上是在起作用?另外,为什么我的示例中的代码不起作用?请注意,它可以很好地编译,只是在运行时就崩溃了。

c 方式(可以说是只有正确的方法(是单独关注

foo不是(或不应该是(foo-finder。它应该做一些事情,而不是陷入困境的事情。

上一个新课程充当您的foo的光标或迭代器。

这是一个稍微扩展的版本,其中Foo_cursor记得它穿过Foo堆栈的旅程。可能对您的问题过度杀伤,但它证明了将Foo-Navigation Logic与Foo-Implentation Logic分开的原则。

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

#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

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

foo& setAsNode() { 
    auto this_copy = *this;
    *originalNode = std::move(this_copy); 
    return *originalNode; 
}

这将起作用,您仍然必须小心不要在分配给*originalNode后使用this。另一个解决方案是在预定分配之前控制originalNode的儿童矢量。在此版本中,this一直有效,直到方法返回,但是如果以下分配引发了例外,则树将保持无效状态。

foo& setAsNode() { 
    auto original_vect = std::move(originalNode->children);
    *originalNode = *this;
    return *originalNode; 
}

总的来说,我会谨慎地设计,要求对象自杀。它暗示对象控制自己的所有权或所有权责任是周期性的。