如何在不进行拷贝初始化的情况下通过对象指针获取原对象?
问题描述
我需要处理一个链表结构,节点通过指针互相链接,第一个节点的ptrTo指向第二个节点的this指针。现在有一个函数Interface,参数是LinkNode的引用r_node,遇到了以下问题:
- 直接用
r_node = r_node.forward()不符合预期:引用不能重新赋值,这条语句会把forward()返回的对象内容拷贝到r_node本身,而不是切换到下一个节点。 - 不想用指针语法(比如
nodeptr->xxx):因为代码里已经有几百次对象调用的语法(node.xxx),改动成本太高。 - 不能修改
forward()函数或新增成员函数,且forward()返回的是引用而非指针。 - 拷贝对象(比如
LinkNode node = r_node)会导致问题:因为链表依赖原对象的this指针,拷贝会生成新对象,破坏链表结构。 - 普通引用(比如
LinkNode& node = r_node)无法重新赋值,node = node.forward()同样只能拷贝内容,不能切换节点。
现有代码
Interface.cpp
#include "node.h" void Interface(LinkNode& r_node){ LinkNode* nodeptr = &r_node; // 我想在这里从nodeptr或r_node创建一个可切换的对象引用 node=node.forward(); }
node.h
#pragma once #include <string> // 补充原代码遗漏的头文件 class LinkNode{ private: std::string payload=""; LinkNode* ptrTo = nullptr; LinkNode* ptrBack = nullptr; public: LinkNode(std::string payload=""){ this->payload=payload; } ~LinkNode(){} LinkNode* getPtr() { return this; } void setPtrTo (LinkNode* ptr){ ptrTo = ptr; } void setPtrBack (LinkNode* ptr){ ptrBack = ptr; } LinkNode& forward() { return *ptrTo; } LinkNode& backward() { return *ptrBack; } };
main.cpp
#include <iostream> #include <stdlib.h> #include <string> // 补充原代码遗漏的头文件 #include "node.h" void Interface(LinkNode& node); int main(){ int lengthofLink=0; std::cout<<"Submit your length of link: "<<std::endl; std::cin>>lengthofLink; LinkNode** array{ new LinkNode* [lengthofLink]{} }; /* 确定节点数据并将指针存入数组 */ for(int i=0;i<lengthofLink;i++){ std::string data; std::cout<<"Enter "<<i+1<<". payload: "; std::cin>>data; array[i] = new LinkNode (data); // array[i]保存new返回的指针 } for(int i=0; i<lengthofLink-1; i++){ // 正向链接 LinkNode* t_ptr_f = array[i+1]->getPtr(); array[i]->setPtrTo(t_ptr_f); } for(int i=lengthofLink; i>=2 ; i--){ // 反向链接 LinkNode* t_ptr_b = array[i-2]->getPtr(); array[i-1]->setPtrBack(t_ptr_b); } LinkNode& r_node = *(array[0]); Interface(r_node); // 释放内存 for(int i=0;i<lengthofLink;i++){ delete array[i]; } delete[] array; return EXIT_SUCCESS; }
解决方案
可以使用std::reference_wrapper实现可重新绑定的引用,它既保留了对象调用的语法,又能像指针一样切换指向的节点。修改后的Interface.cpp代码如下:
#include "node.h" #include <functional> // 必须包含此头文件以使用std::reference_wrapper void Interface(LinkNode& r_node){ // 用reference_wrapper包装初始节点 std::reference_wrapper<LinkNode> node = r_node; // 切换到下一个节点:重新绑定reference_wrapper,无对象拷贝 node = node.get().forward(); // 保留类似对象的调用语法,两种写法都可行 std::cout << "当前节点payload:" << node.get().payload << std::endl; std::cout << "当前节点payload:" << node->payload << std::endl; }
关键说明
std::reference_wrapper<T>是可拷贝、可赋值的包装类,内部保存对象引用,通过get()可获取原始引用,也可直接用->调用成员函数(类重载了该操作符)。node = node.get().forward():node.get()返回当前包装的节点引用,调用forward()得到下一个节点的引用,赋值给node即可完成节点切换,全程无对象拷贝,完全复用原链表节点。- 原有
node.xxx的调用只需改为node->xxx或node.get().xxx,改动量极小,保留了熟悉的对象调用语法。
内容的提问来源于stack exchange,提问作者hmetust
相关产品推荐
相关产品推荐

