替代使用智能指针将rvalue引用绑定到抽象类

时间:2016-05-19 19:31:07

标签: c++ c++11 arduino rvalue-reference

更新

事实证明,STL的某些部分实际上可以使用 - 但是由于严重的内存限制而非常谨慎。 Arduino对我来说是一个新的平台,在看到很多帖子谈到缺乏对STL甚至some ports的支持之后,我只是认为它无法使用。

既然我知道我可以使用unique_ptr,那么我原来的问题就没有任何意义了。无论如何,我会留在这里,以防它对某人有用。

------

我在Arduino项目中创建了一个C ++类 - 这意味着STL不可用(例如,没有智能指针)。目前我有以下内容:

class ntp_client {
public:
  ntp_client(UDP& udp) : udp_(udp) {}

  // ...

private:
  UDP& udp_;
};

UDP是其他类的基本抽象类,例如WiFiUDPEthernetUDP。现在我的代码看起来像:

WiFiUDP udp;
ntp_client ntp(udp);

但是,我也希望能够做到以下几点:

ntp_client ntp{WiFiUDP{}};

所以,我正在考虑添加一个带右值引用的构造函数,但我认为没有办法将rvalue引用绑定到类属性(因为UDP是一个抽象类)。

是否可以在不使用智能指针或模板的情况下执行此操作?

4 个答案:

答案 0 :(得分:2)

不,如果没有智能指针或模板,就无法做你正在做的事情。执行ntp_client ntp{WiFiUDP{}};后,WiFiUDP对象将超出范围并被破坏。您无法使用对udp的右值引用来捕获它,因为您无法为其分配空间,无论是作为成员还是作为堆。

如果你真的想做类似的事情,你需要让ntp_client知道要分配多少内存(通过模板),或者在其他地方分配*UDP并在其中存储指针ntp_client。如果您只需要使用udp中的ntp_client对象,那么您可以添加一个指向udp的构造函数,您可以将其称为ntp_client ntp{new WiFiUDP()};并添加{ {1}}在ntp_client析构函数中。或者,您可以实现一个简单的未模板delete类,该类实现围绕udpsmartpointer指针的引用计数,并为您执行udpnew

总的来说,我认为最好的解决方案就是您已经拥有的代码!

答案 1 :(得分:1)

我会重新审视你的设计。我会这样做:

class ntp_client {
public:
  template<class UDP_IMPL, ARGS...>
  ntp_client(ARGS&&... args) : udp_(my::make_unique<UDP_IMPL>(std::forward(ARGS)args...))
                               { }

private:
  my::unique_ptr<UDP> udp_ptr;
};

my::unique_ptrmy::make_unique的实施仅作为练习,因为它很简单。

说明 - 不要将引用保留在您不想拥有的内容中。相反,构建正确的实现并保留它。

答案 2 :(得分:1)

如果你想构造带有r值引用的ntp_client(即临时),你需要将临时值放在某个地方。

逻辑位置将在ntp_client内部,或者从它派生的东西。

这开始争论一个工厂函数,它使ntp_client具有封装的wifi或以太网UDP,或者引用一个。

  

是否可以在不使用智能指针或模板的情况下执行此操作?

是的,但模板可以更轻松地减少打字...

#include <utility>

struct UDP {};

struct WiFiUDP : UDP {};
struct EthernetUDP : UDP {};


class ntp_client {
public:
  ntp_client(UDP& udp) : udp_(udp) {}

  // ...

private:
  UDP& udp_;
};

class Wifi_ntp_client : public ntp_client
{
  // take care - the base class reference is initialised before the stored
  // object. You must not use it in the base class constructor
  // or destructor!
  Wifi_ntp_client(WiFiUDP&& w)
    : ntp_client(_store)
    , _store(std::move(w))
  {}

  WiFiUDP _store;
};

class Ethernet_ntp_client : public ntp_client
{
  // take care - the base class reference is initialised before the stored
  // object. You must not use it in the base class constructor
  // or destructor!
  Ethernet_ntp_client(EthernetUDP&& e)
    : ntp_client(_store)
    , _store(std::move(e))
  {}

  EthernetUDP _store;
};

int main()
{
  WiFiUDP a;
  ntp_client aa(a);

  EthernetUDP b;
  ntp_client bb(b);

  Wifi_ntp_client c(WiFiUDP());
  Ethernet_ntp_client d(EthernetUDP());

}

答案 3 :(得分:0)

如果你让UDP的接口的一部分有一个克隆方法创建一个副本(实际的派生类)并返回一个指向新对象的指针,那么你可以让你的构造函数采用一个r -value reference,克隆它,并将其存储在UDP *中,并确保在析构函数中调用delete。

ntp_client(UDP& udp) : udp_(udp.clone()) {}
UDP * udp_ = nullptr;
~ntp_client(){delete udp_;}