Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 取消引用指针以获取引用是否错误?_C++_Pointers_Stl_Reference - Fatal编程技术网

C++ 取消引用指针以获取引用是否错误?

C++ 取消引用指针以获取引用是否错误?,c++,pointers,stl,reference,C++,Pointers,Stl,Reference,我更喜欢在任何地方使用引用,但在使用STL容器时,必须使用指针,除非您真的想通过值传递复杂类型。我觉得把它转换成一个参考文献是肮脏的,这似乎是错误的 是吗 为了澄清 MyType *pObj = ... MyType &obj = *pObj; 这不是“脏”吗,因为你可以(即使只是在理论上,因为你先检查它)取消对空指针的引用 编辑:哦,你不知道这些对象是否是动态创建的。否。你还可以如何实现操作符=?您必须取消引用此,才能返回对自己的引用 请注意,尽管我仍然会按值将项目存储在STL容器中

我更喜欢在任何地方使用引用,但在使用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';
}