更新
事实证明,STL的某些部分实际上可以使用 - 但是由于严重的内存限制而非常谨慎。 Arduino对我来说是一个新的平台,在看到很多帖子谈到缺乏对STL甚至some ports的支持之后,我只是认为它无法使用。
既然我知道我可以使用unique_ptr
,那么我原来的问题就没有任何意义了。无论如何,我会留在这里,以防它对某人有用。
------
我在Arduino项目中创建了一个C ++类 - 这意味着STL不可用(例如,没有智能指针)。目前我有以下内容:
class ntp_client {
public:
ntp_client(UDP& udp) : udp_(udp) {}
// ...
private:
UDP& udp_;
};
UDP
是其他类的基本抽象类,例如WiFiUDP
或EthernetUDP
。现在我的代码看起来像:
WiFiUDP udp;
ntp_client ntp(udp);
但是,我也希望能够做到以下几点:
ntp_client ntp{WiFiUDP{}};
所以,我正在考虑添加一个带右值引用的构造函数,但我认为没有办法将rvalue引用绑定到类属性(因为UDP是一个抽象类)。
是否可以在不使用智能指针或模板的情况下执行此操作?
答案 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
指针的引用计数,并为您执行udp
和new
。
总的来说,我认为最好的解决方案就是您已经拥有的代码!
答案 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_ptr
和my::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_;}