繁体   English   中英

在 C++ 中从指针转换为引用

[英]convert from pointer to reference in C++

我想使用new创建一个类的实例,但我想转换为引用以供进一步使用而不是使用指针。 目前我正在使用这一行Foo& rf = *f; 显式转换,似乎有点傻。 有没有更好更优雅的方法来创建引用变量并引用new创建的实例?

这里有一些代码来显示我在做什么,

class Foo{
    public:
    Foo(){

    }

    void printValue() {
        cout << "This is Foo object " << endl;
    }
};

int main() {
    Foo* f = new Foo();
    Foo& rf = *f;
    rf.printValue();
    f -> printValue();
}

你可以这样写:

Foo* foo = new Foo();
Foo& fooRef = *foo;

在一行中:

Foo& fooRef = *new Foo();

但是,请注意,无论如何您都应该稍后删除分配的内存:

delete &fooRef;

我不建议您以这种方式编写代码,以避免内存泄漏。 查看此答案以获取更多详细信息。 尽可能选择智能指针或容器。

...转换为引用以供使用指针以外的进一步使用。

我更喜欢代码深处的引用(并避免使用指针)。 主要是因为 nullptr 可能具有特殊含义(引用不会),需要一些思考来确认,下次我查看代码时。

我的解决方案是新建大于自动内存的对象,以便在生命周期内获得适当级别的指针。 然后我使用解除引用的指针调用 using 方法或函数。 这使指针(在生命周期开始时,例如 main)保持原样,稍后仍可用于删除。

// bigData  used many places
void use1_of_Data (BigData_t& bigData, Small_t& sd) {
    //... do something with data
}

void use2_of_Data (BigData_t& bigData, Small_t& sd) {
    //... do something with data
}

//...
void use3_of_Data (BigData_t& bigData, Small_t& sd) {
    //... do something with data
}

int main(int argc, char* argv[]) 
{
   // ...
   BigData_t* bd = new BigDta_t; // (sizeof(BigData_t) > autovar space)
   Small_t    sd;
   {
      assert(nullptr != bd); 
      // note - bd lasts the lifetime of program

      use1_of_Data (*bd, sd);
      use2_of_Data (*bd, sd);
      //...
      use3_of_Data (*bd, sd);
   }
   // what's new'd in main, is deleted in main
   delete bd;        
}

正如其他人所说,如果 Foo 实例的非堆内容不是太大以至于 Foo 实例本身需要在堆上分配,最好只使用堆栈:

Foo foo;
foo.printValue();

但是,如果由于某种原因确实需要在堆上分配它,那么在普通指针中保存对它的唯一引用是危险的,因为如果任何代码抛出异常,它将永远不会被释放。 事实上,大多数现代 C++ 指南建议不要使用普通指针指向自己的数据,原因如下:

Foo * fooPtr = new Foo();
doSomething();  // If an exception is thrown here, the Foo never gets deallocated!
Foo& foo = *fooPtr;
foo.printValue(); // If printValue throws an exception, the Foo never gets deallocated!
delete foo;

如果您不熟悉此类问题,我建议您使用谷歌搜索 RAII(“资源获取即初始化”),这是在使用 C++ 编程时理解的一个关键概念。

在这种情况下实现 RAII 的一种简单方法是使用智能指针(std::shared_ptr 或 std::unique_ptr)。

额外的引用变量仍然有助于避免必须使用箭头运算符来调用智能指针上的函数。 我不同意其他一些回答者的观点,他们在将本地引用绑定到本地指针中已经存在的值时也看不到价值。 我更喜欢尽可能使用引用,因为当我使用引用时,我可以确定引用不是空的(引用应该总是引用实际对象),而当我使用指针(甚至是智能指针)时,我必须始终小心我的代码正确处理指针为空的情况。 当指针初始化发生在接近指针的使用时,这可能没什么大不了的,但是当它们分开时,就很难通过代码来确定指针不能为空。 一个参考使这个自我记录。

我认为首先确保指针或智能指针值不能为空,然后将本地引用绑定到指向的值通常很有用,因为我可以自由地使用引用而不必担心每次使用关于它为空的可能性:

std::unique_ptr<Foo> fooPtr = std::make_unique<Foo>(/* Foo constructor args go here */);
doSomething(); // Now if an exception thrown here, Foo gets deallocated.
Foo& foo = *fooPtr; // We know the pointer is not null here (it just
                    // got returned from make_unique which
                    // didn't throw a bad_alloc exception) so it's
                    // safe to bind a reference to it here.
                    // Also, this reference has lifetime less than the
                    // smart pointer, so will never outlive it.

// .. many lines of code later ..
foo.printValue(); // No need to worry about null here.
                  // If exception thrown here, the unwinding of the stack
                  // causes fooPtr to deallocate Foo.

// No need to call delete here.
// fooPtr will automatically deallocate Foo when it goes out of scope.

如果我们谈论优雅,我可以建议您使用 shared_ptr 吗?

#include <iostream>
#include <memory>

using namespace std;

class Foo{
    public:
    Foo(){

    }

    void printValue() {
        cout << "This is Foo object " << endl;
    }
};

int main(int argc, char *argv[])
{
    Foo* f = new Foo();
    std::shared_ptr<Foo> mySharedPtr(f);
    f->printValue();
    mySharedPtr.get()->printValue();

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM