例如,我有这段代码。
#include <iostream>
using namespace std;
int main()
{
int x = 5; //Original variable
int &y = x; //Reference variable to x.
y = 10; //Modifying reference variable.
cout<<x<<" "<<y<<endl;
x = 5; //Modifying original variable.
cout<<x<<" "<<y<<endl;
}
它给出了预期的输出。
10 10
5 5
显示修改原始变量或引用变量都会改变它们 - 非常明显。
我的问题是:
我知道它不会被称为参考变量。功能
为了使事情更清楚,
修改x
应修改y
,但修改y
不应修改x
。也就是说,y
应该是x
的独立副本,但应该在x
更改时更改。
这可能吗?
是的,我可以创建自己的逻辑来模拟这个,但我想知道C ++默认是否适应这种情况。
答案 0 :(得分:2)
没有语言结构能够立即为您提供所需的内容,但您可以通过封装x和y来相当简单地实现它。
struct XChangesY{
set_x(int x_and_y){ y = x = x_and_y; }
set_y(int y_){ y = y_; }
int get_x(){ return x; }
int get_y(){ return y; }
private:
int x;
int y;
}
答案 1 :(得分:1)
不,你想做什么是不可能的。考虑如果同时修改y
和x
会发生什么。那么y
取其价值在哪里?来自x
的更新值,该值应修改x
和y
,或更新y
的值,该值应仅更新y
而不是{{} 1}}?
唯一的出路是实现自己的逻辑。无论如何,您需要有两个x
变量。
答案 2 :(得分:1)
当然,但它并不优雅 -
template<typename T>
class C
{
public:
C(T t) : m_t(new T(t)), t_local(t), is_copy(false) {}
C(const C& c) : m_t(c.m_t), t_local(t), is_copy(true) {}
T Get() { return *m_t; }
T GetLocal() { return t_local; }
void Set(T t)
{
t_local = t;
if (!is_copy) *m_t = t;
}
private:
T* m_t;
T t_local;
bool is_copy;
};
在评估y
之后,您的设置会产生歧义,在它被更改之后 - 您想要x
的值,还是{{1}的新的不同值}}?我没有办法避免为每种情况创建单独的方法。
答案 3 :(得分:1)
C ++不提供自动执行此操作的机制,但您可以创建一个支持您尝试执行此操作的类。
以下是您可以做的非常简单的版本:
class IntRef {
int *ptr;
int copy;
public:
IntRef(int& d) : ptr(&d) {}
IntRef& operator=(const int& rhs) {
// Detach from the original on assignment
copy = rhs;
ptr = ©
}
operator int() const {
return *ptr;
}
};
int main() {
int x = 5; //Original variable
IntRef y(x); //Reference variable to x.
x = 5; //Modifying original variable.
cout<<x<<" "<<y<<endl;
y = 10; //Modifying reference variable.
cout<<x<<" "<<y<<endl;
return 0;
}
打印
5 5
5 10
上面实现的想法是,只要未分配y
,就保持指针指向原始值。分配后,指针切换到内部保存的副本。
答案 4 :(得分:1)
您正在寻找的内容并非固有地内置于该语言中 - 两个变量共享相同的值,更改一个更改两个但更改另一个只更改一个。
这个问题虽然类似于共享指针和引用计数器。例如,当您复制std::string
时,不会复制字符串的内容。创建一个新的string
对象,其中包含指向与第一个字符串相同的数据的指针,以及一个引用计数器。
因此两个字符串共享相同的数据。但是当你改变一个 - 任何一个 - 并且引用计数器不止一个时,那个string
会自我分离并复制数据,并且两个字符串都不再链接。这是为了避免在没有必要时重复长串数据。
Qt容器(QByteArray
,QMap
,QList
,...)也会发生同样的事情。
另一种查看问题的方法是观察者的逻辑 - 从外部接收的数据更新内部值,但内部值可以通过其他方式更改。 Qt的信号/插槽功能可以自然地用来做,或者你可以轻松实现自己的逻辑来自己做。
答案 5 :(得分:1)
似乎你想要的是 copy-on-write 语义。这样的事情可能适合你,但很容易被滥用:
template <class T>
class cow_ptr
{
public:
using ref_ptr = std::shared_ptr<T>;
private:
ref_ptr m_sp;
bool m_original; //don't detach the original
void detach()
{
T* tmp = m_sp.get();
if( !( tmp == 0 || m_sp.unique() || m_original ) ) {
m_sp = ref_ptr( new T {*tmp} );
}
}
public:
cow_ptr(T* t)
: m_sp{t}, m_original{true}
{}
cow_ptr(const ref_ptr& refptr)
: m_sp{refptr}, m_original{true}
{}
cow_ptr(const cow_ptr& cowptr)
: m_sp{cowptr.m_sp}, m_original{false}
{}
cow_ptr& operator=(const cow_ptr& rhs)
{
m_sp = rhs.m_sp;
return *this;
}
const T& operator*() const
{
return *m_sp;
}
T& operator*()
{
detach();
return *m_sp;
}
const T* operator->() const
{
return m_sp.operator->();
}
T* operator->()
{
detach();
return m_sp.operator->();
}
};
然后你可以像这样使用它:
int main()
{
auto x = cow_ptr<int>{ new int{5} };
auto y = x;
const auto &yr = y; //so dereferencing doesn't detach
cout<<*x<<" "<<*yr<<endl; //5 5
*x = 10;
cout<<*x<<" "<<*yr<<endl; //10 10 (updating x updated y)
*y = 15;
cout<<*x<<" "<<*yr<<endl; //10 15 (updating y did not update x)
//from now on, changing x will not change y
}