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

时间:2015-06-28 15:13:51

标签: c++ pointers c++11 reference rvalue

我有以下代码:

bitraverse id pure :: (Maybe a, b) -> Maybe (a, b)

如何将其转化为参考文献?
注意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

但有人告诉我这是不好的风格,必须避免。

3 个答案:

答案 0 :(得分:2)

Rvalue参考有移动sematics。将B移动为A时,这种方法效果不佳。

使用左值参考:

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);

答案 1 :(得分:1)

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

void f(int& i);

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

问题在于C ++中的原始指针正是这样 - 它们没有自动生命周期范围,并且通过转换为左值引用,您建议了一个实例具体且不应被接收方销毁的契约。

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

Modern 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应该具有给定分配的地址(它假设所有权,如果不是delete d,则release将在退出范围内进行分配。

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

---编辑---

基于OP的评论:

首先请注意

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

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

但请记住,这是一个堆栈变量 - 它具有自动生命周期,并将在当前范围结束时到期。

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

理论上,您可以用

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

但重要的是list_add是否期望保持对象,直到你从列表中删除它...这通常是一个基于列表的函数,它采用指针期待。如果它采用非const引用,它也可以这样做。

回答你原来的帖子::

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,然后再次复制到列表中,这是一种耻辱,但至少它不会崩溃。

答案 2 :(得分:0)

你的代码有点不安全。 首先,如果a为空,该怎么办?你没有检查它。
第二,如果指向堆栈对象或数据段对象怎么办?你会有意想不到的行为(=大多数操作系统崩溃)。

如果您的对象必须动态分配,请使用std::shared_ptr

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