C++ 取消引用指针以获取引用是否错误?
我更喜欢在任何地方使用引用,但在使用STL容器时,必须使用指针,除非您真的想通过值传递复杂类型。我觉得把它转换成一个参考文献是肮脏的,这似乎是错误的 是吗 为了澄清C++ 取消引用指针以获取引用是否错误?,c++,pointers,stl,reference,C++,Pointers,Stl,Reference,我更喜欢在任何地方使用引用,但在使用STL容器时,必须使用指针,除非您真的想通过值传递复杂类型。我觉得把它转换成一个参考文献是肮脏的,这似乎是错误的 是吗 为了澄清 MyType *pObj = ... MyType &obj = *pObj; 这不是“脏”吗,因为你可以(即使只是在理论上,因为你先检查它)取消对空指针的引用 编辑:哦,你不知道这些对象是否是动态创建的。否。你还可以如何实现操作符=?您必须取消引用此,才能返回对自己的引用 请注意,尽管我仍然会按值将项目存储在STL容器中
MyType *pObj = ...
MyType &obj = *pObj;
这不是“脏”吗,因为你可以(即使只是在理论上,因为你先检查它)取消对空指针的引用
编辑:哦,你不知道这些对象是否是动态创建的。否。你还可以如何实现
操作符=
?您必须取消引用此
,才能返回对自己的引用
请注意,尽管我仍然会按值将项目存储在STL容器中——除非您的对象很大,否则堆分配的开销将意味着您将使用更多的存储,并且效率较低,如果只是按值存储项,则情况会更糟。在尝试将指针转换为引用之前,请确保指针不为NULL,并且只要引用存在,对象将保持在范围内(或在引用堆时保持分配),您就可以了,道德上讲是干净的:)如果您希望容器实际包含动态分配的对象,那么不应该使用原始指针。使用
unique\u ptr
或任何合适的类似类型。使用取消引用的指针初始化引用绝对没有问题,没有任何问题。如果p
是一个指针,并且如果取消引用它是有效的(例如,它不是空的),那么*p
就是它指向的对象。可以将引用绑定到该对象,就像将引用绑定到任何对象一样。显然,您必须确保引用不会比对象更长寿(就像任何引用一样)
例如,假设我被传递了一个指向对象数组的指针。它也可以是迭代器对、对象向量或对象映射,但为了简单起见,我将使用数组。每个对象都有一个函数,order
,返回一个整数。我要对每个对象调用一次bar
函数,顺序是增加顺序
值:
void bar(Foo &f) {
// does something
}
bool by_order(Foo *lhs, Foo *rhs) {
return lhs->order() < rhs->order();
}
void call_bar_in_order(Foo *array, int count) {
std::vector<Foo*> vec(count); // vector of pointers
for (int i = 0; i < count; ++i) vec[i] = &(array[i]);
std::sort(vec.begin(), vec.end(), by_order);
for (int i = 0; i < count; ++i) bar(*vec[i]);
}
空栏(Foo&f){
//做点什么
}
按订单交货(Foo*lhs,Foo*rhs){
返回lhs->order()order();
}
按顺序(Foo*数组,int计数)无效调用{
std::vector vec(count);//指针的向量
对于(int i=0;i
我的示例初始化的引用是一个函数参数,而不是直接的变量,但我可以有效地执行以下操作:
for (int i = 0; i < count; ++i) {
Foo &f = *vec[i];
bar(f);
}
for(int i=0;i
显然,向量
是不正确的,因为我会按顺序在每个对象的副本上调用条
,而不是按顺序在每个对象上调用bar
采用非常量引用,因此,除了性能或其他方面之外,如果bar
修改输入,这显然是错误的
智能指针向量或boost指针向量也是错误的,因为我不拥有数组中的对象,当然也不能释放它们。对原始数组进行排序也可能是不允许的,或者在这种情况下,如果它是
映射而不是数组,则不可能进行排序。我的回答并没有直接解决您最初的问题,但您似乎遇到了这个问题,因为您有一个存储指针类型的STL容器
Boost提供了解决这些情况的库。例如,ptr_向量
在内部存储指向类型的指针,但通过其接口返回引用。注意,这意味着容器拥有指向实例的指针,并将管理其删除
这里有一个简单的例子来说明这个概念
#include <string>
#include <boost/ptr_container/ptr_vector.hpp>
void foo()
{
boost::ptr_vector<std::string> strings;
strings.push_back(new std::string("hello world!"));
strings.push_back(new std::string());
const std::string& helloWorld(strings[0]);
std::string& empty(strings[1]);
}
#包括
#包括
void foo()
{
boost::ptr_向量字符串;
strings.push_back(新std::string(“helloworld!”);
strings.push_back(新std::string());
常量std::string和helloWorld(strings[0]);
std::string&空(strings[1]);
}
它没有什么问题,但请注意,在机器代码级别上,引用通常与指针相同。因此,当指针被分配到引用时,通常不会真正解除引用(没有内存访问)。
因此,在现实生活中,引用可以是0,并且在使用引用时会发生崩溃-这可能比它的assignemt晚得多
当然,发生的事情在很大程度上取决于编译器版本和硬件平台,以及编译器选项和引用的确切用法
正式地说,取消引用0指针的行为是未定义的,因此任何事情都可能发生。这包括它可能会立即崩溃,但也可能会在很久以后崩溃或永远不会崩溃
因此,请始终确保您从未将0指针指定给引用-像这样的错误很难找到
编辑:将“通常”改为斜体,并添加了关于官方“未定义”行为的段落
我更喜欢在任何地方使用引用,但在使用STL容器时,必须使用指针,除非您真的想通过值传递复杂类型
需要明确的是:STL容器被设计为支持某些语义(“值语义”),例如“容器中的项目可以被复制”。由于引用不可重新绑定,它们不支持值语义(即,尝试创建std::vector
或std::list
)。您不能在STL容器中放置引用,这是正确的
通常,如果使用引用而不是普通对象,那么要么使用基类并希望避免切片,要么尝试避免复制。而且,是的,这意味着如果您想存储站点
#include <iostream>
#include <vector>
// note signature, inside this function, i is an int&
// normally I would pass a const reference, but you can't add
// a "const* int" to a "std::vector<int*>"
void add_to_vector(std::vector<int*>& v, int& i)
{
v.push_back(&i);
}
int main()
{
int x = 5;
std::vector<int*> pointers_to_ints;
// x is passed by reference
// NOTE: this line could have simply been "pointers_to_ints.push_back(&x)"
// I simply wanted to demonstrate (in the body of add_to_vector) that
// taking the address of a reference returns the address of the object the
// reference refers to.
add_to_vector(pointers_to_ints, x);
// get the pointer to x out of the container
int* pointer_to_x = pointers_to_ints[0];
// dereference the pointer and initialize a reference with it
int& ref_to_x = *pointer_to_x;
// use the reference to change the original value (in this case, to change x)
ref_to_x = 42;
// show that x changed
std::cout << x << '\n';
}