参考变量的单向修改
One way modification of reference variables
例如,我有这样的代码。
#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++是否默认满足了这一点
没有一种语言结构可以立即为您提供所需的内容,但您可以通过封装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;
}
不,你想做的是不可能的。考虑一下如果同时修改y
和x
会发生什么。那么y
的取值在哪里?根据应同时修改x
和y
的x
的更新值,还是根据应仅更新y
而不更新x
的y
的更新值?
唯一的前进道路是实现自己的逻辑。在任何情况下,都需要有两个int
变量。
当然,但它并不优雅--
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
的值,还是y
的新的不同值?我看不出有任何方法可以避免为每个案例创建单独的方法。
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
,就保持指向原始值的指针。赋值后,指针切换到内部保存的副本。
您所寻找的并不是内置的语言——两个变量共享相同的值,更改一个变量会同时更改两个变量,但更改另一个变量只会更改一个。
不过,这个问题类似于共享指针和引用计数器。例如,当您复制std::string
时,不会复制字符串的内容。创建一个新的string
对象,该对象具有指向与第一个字符串相同的数据的指针和引用计数器。
因此,两个字符串共享相同的数据。但是,当您更改一个(任意一个)并且引用计数器不止一个时,则string
会自行取消关联并复制数据,并且两个字符串不再链接。这是为了在不需要时避免重复的长数据串。
同样的情况也发生在Qt容器(QByteArray
、QMap
、QList
…)上
另一种看待问题的方法是观察者逻辑——从外部接收的数据会更新内部值,但内部值可以通过其他方式更改。Qt的信号/插槽功能可以很自然地做到这一点,也可以很容易地实现自己的逻辑来实现这一点。
似乎您想要的是写时复制语义。像这样的东西可能对你有用,但很容易被滥用:
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
}
- 如何从子成员函数修改父公共成员变量
- 修改程序的入口点时未调用全局变量的构造函数
- 为什么从另一个构造函数内部调用C++构造函数不修改类变量?
- 如何使用gmock模拟修改C++类中私有变量的成员函数
- 有了memory_order_relaxed,原子变量的总修改顺序如何在典型体系结构上得到保证
- 我们如何修改常量变量的值
- 是否可以禁止在for循环体内部修改循环变量
- 使用 QtConcurrent::run() 修改成员变量?
- 在 C++17 中修改 constexpr 函数中的全局变量
- 是否可以在不修改父类的情况下将成员变量初始化推迟到继承的类?
- 如何修改用户指定的变量?
- 打印/修改类对象的特定成员变量,其类定义列表 (STL) 包含的元素类型
- 在击中断点并继续执行VS时,如何在运行时自动修改变量的值
- C 如何使DLL从主线程修改变量
- 使用gcc插件修改变量声明的顺序
- 从子 DLL 访问/修改变量
- QThread:从不同线程修改变量的安全方法
- C++继承子类可修改变量
- 由于在序列点之间修改变量两次而导致的 UB 是否会转移到"inner"范围?
- assert()修改变量时发出警告