C++ C++;班级变动什么*这";指
我有一个类“foo”,它包含一个成员向量,其中包含类型为“foo”的元素。这个类有一个名为“make”的方法,它创建“foo”对象并将它们附加到向量。我还提供了一种导航“foo”对象的方法,它的“foo”向量元素称为“get” 我想重新分配任何“foo”对象上的“this”所指内容,以指向其向量中的一个foo对象。我想为代码提供这个功能,作为一种更有效地导航和跟踪foo对象的方法,而不必将引用绑定到特定的“foo”成员。我试图通过一个名为“setAsNode”的方法来实现这一点,该方法重新分配“*this”是什么 下面是我模拟的一些示例代码,我相信这些代码能让我的观点得到理解: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”的方法来实现这一点,该方法重新分配“
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