c++从动态分配转换为引用

c++ translate from dynamic allocation to references

本文关键字:引用 转换 动态分配 c++      更新时间:2023-10-16

我有以下代码:

class A{
public:
    virtual do_something() = 0;
}
class B : public A{
public:
    virtual do_something() override;
}
void use_a(A *a){
   if (a){
      a->do_something();
      delete a;
   }
}
use_a( new B() );

如何将其转化为参考文献
注意,do_something()不是const方法。我以为它可以是这样的:

void use_a(A &&a){
   a->do_something();
}
use_a( B() );

但有人告诉我,这是一种糟糕的风格,必须避免。

Rvalue引用具有移动语义。当将CCD_ 3移动为CCD_。

使用左值参考:

void use_a(A &a);
B b;
use_a(b);

或模板:

template <typename T>
void use_a(T &&a);

或者,如果它不需要是引用,则是一个智能指针:

void use_a(std::unique_ptr<A> a);
void use_a(std::shared_ptr<A> a);

很简单,您可以通过提供一个具体实例将指针转换为引用,即取消引用:

void f(int& i);
f(*(new int)); // do not do this!

问题是C++中的原始指针正是这样的——它们没有自动的生存期范围,通过转换为左值引用,您已经建议了一个约定,即实例是具体的,不应该被接收器破坏。

int* ptr = new int;
f(ptr);
delete ptr; // otherwise it leaked

现代C++使用RAII来提供受控的自动寿命管理,C++11引入了unique_ptrshared_ptr来处理指针。在C++14中,我们还拥有完全避免原始指针的机制。

std::unique_ptr<int> ptr = std::make_unique<int>(/* ctor arguments here */);
f(ptr.get());
// now when ptr goes out of scope, deletion happens automatically.

另请参阅http://en.cppreference.com/w/cpp/memory/unique_ptr

在任何时候,只有一个std::unique_ptr应该具有给定分配的地址(它承担所有权,如果不是released,则将delete作为退出作用域上的分配)。

对于引用计数的指针:http://en.cppreference.com/w/cpp/memory/shared_ptr

---编辑---

根据作战人员的意见:

首先注意

Pair p = { "one", "two" };
// and
Pair p("one", "two");
Pair p{"one", "two"};

是同义的,在所有情况下,它们通过分配堆栈空间并调用Pair::Pair("one", "two")在那里构造Pair对象来创建堆栈局部变量p

但是,请记住,这是一个堆栈变量——它有一个自动生存期,将在当前作用域结束时过期。

{ Pair p{"one", "two"}; list_add(list, p); } //p is destroyed

理论上,你可以用代替它

list_add(list, Pair{"one", "two"});

但重要的是list_add是否希望保留该对象,直到您将其从列表中删除。。。这通常是接受指针的基于列表的函数所期望的。如果它采用一个非常数引用,它也可以这样做。

要回答您的原始帖子::

struct A { virtual void doSomething() {} };
struct B : public A { virtual void doSomething() override() {} };
void useDoSomethingInterface(A& a) {
    a.doSomething();
}
int main() {
    A a;
    B b;
    useDoSomethingInterface(a);
    useDoSomethingInterface(b);
}

考虑以下内容:

void list_add(IList& list, Pair& pair) {
    pair.next = list.head;
    list.head = &pair; // << BAD NEWS
}
void badness(IList& list) {
    list_add(list, Pair("hello", "world"));
}
void caller() {
    IList list;
    badness(list);
    // list.head now points to a destroyed variable on the stack

C++中的C指针是原始的机器级指针。他们不算裁判。C++对象实例有一个固定的、定义良好的生存期:直到作用域结束。

但是,如果list_add按值获取数据

void list_add(IList& list, Pair pair)

然后我们就可以了。我们创建的临时Pair必须复制一次才能创建pair,然后再复制到列表中,这很遗憾,但至少它不会崩溃。

您的代码有点不安全。首先,如果a为null怎么办?您没有检查。
第二,如果a指向堆栈对象或数据段对象,该怎么办?你会有意想不到的行为。

如果您的对象必须动态定位,只需使用std::shared_ptr

void use_a(std::shared_ptr<A>& a){
   a->do_something();
}