所以,我遇到了一个问题,我不确定它是语言问题还是编译器/ GCC问题。C++ - 是否必须定义所有静态类方法,即使未使用?
TL; DR - 我是否需要定义一个类中所有静态方法,即使这些静态方法不会被调用应用程序(即可以被链接器合法下降呢)?
我有一个库类,在微控制器中实现UART的设备驱动程序。因为我不希望多个UART对象指向相同的资源,所以每个UART对象都是一个单独的对象,使用几种GetInstance()
方法之一检索,每个对象用于设备中的每个UART实例(UART0,UART1等)。每个UART实例需要有两个FIFO(Tx和Rx)用于存储。每个FIFO需要通过应用明确地确定大小,并且在UART对象被实例化(理想地)时被分配。所以我也有一些静态的GetStorage()
方法,每个UART还有一次。
我为概念验证创建了一些精简代码。这里的static_instance.h:
#ifndef STATIC_INSTANCE_H_
#define STATIC_INSTANCE_H_
#ifdef __cplusplus
#include <vector>
namespace foo {
class Uart {
public:
/* Retrieve a singleton instance, using lazy static initialization. Note
* that not all instances will be present for a given device. */
static Uart& Uart1GetInstance(void);
static Uart& Uart2GetInstance(void);
static Uart& Uart3GetInstance(void);
/* Does something. */
void DoSomething(void) { ++counter; }
private:
/* Structure for the storage that each static Uart instance requires. */
struct Storage {
Storage(std::vector<char>& vector)
: my_vector_(vector) { }
std::vector<char>& my_vector_; // Buffer for data.
};
/* Instantiate object using provided register base and FIFO structures. */
Uart(int instance, Storage& storage)
: instance_(instance), storage_(storage) { }
~Uart() { }
/* Retrieves the storage required for the static Uart object instances.
* These methods are NOT implemented in static_instance.cc, but must be
* implemented in the application code, only for those Uart instances
* that are invoked in the application. */
static Storage& Uart1GetStorage(void);
static Storage& Uart2GetStorage(void);
static Storage& Uart3GetStorage(void);
int const instance_; // Instance number of this object.
Storage& storage_; // Allocated storage for this object.
int counter = 0; // Dummy counter.
};
} // namespace foo
#endif // __cplusplus
#endif
而这里的static_instance.cc:
#include <static_instance.h>
namespace foo {
Uart& Uart::Uart1GetInstance(void) {
static Uart uart(1, Uart1GetStorage());
return uart;
}
Uart& Uart::Uart2GetInstance(void) {
static Uart uart(2, Uart2GetStorage());
return uart;
}
Uart& Uart::Uart3GetInstance(void) {
static Uart uart(3, Uart3GetStorage());
return uart;
}
} // namespace foo
的想法是,你只叫GetInstance()
你实际需要的UART实例,然后只定义GetStorage()
为UART实例。 (在这个例子中,我只定义了一个缓冲区,并使用std::vector<char>
作为替身。)此外,由应用程序来定义存储方法,因为每个应用程序都将有自己的要求鉴于UART的缓冲区需要。 (我是绝对不会做的是把宏在我的C++模块,因为,EW)下面是main.cc的代码片段实例UART2:
namespace foo {
Uart::Storage& Uart::Uart2GetStorage(void) {
static std::vector<char> rx_vector(256, 0);
static Uart::Storage storage(rx_vector);
return storage;
}
static foo::Uart& uart_ = foo::Uart::Uart2GetInstance();
void wibble(void) {
uart_.DoSomething();
}
} // namespace foo
现在,我正在开发使用较早的应用此芯片早期的IDE(Kinetis Design Studio v3.2.0为好奇),它使用GCC 4.8.4并编译链接没有错误。
但恩智浦已弃用KDS另一个工具链(MCUXpresso 10.0),它使用GCC 5.4.1,并使用完全相同的代码,这个时候我得到两个连接错误:
./source/static_instance.o: In function 'foo::Uart::Uart1GetInstance()':
../source/static_instance.cc:5: undefined reference to 'foo::Uart::Uart1GetStorage()'
./source/static_instance.o: In function 'foo::Uart::Uart3GetInstance()':
../source/static_instance.cc:13: undefined reference to 'foo::Uart::Uart3GetStorage()'
我不确定链接器为什么会关心针对UART1和UART3的GetStorage()
方法没有定义,因为我没有在我的应用程序中为UART1或UART3调用GetInstance()
,因此也不会调用相应的GetStorage()
方法。
我在这里的问题是...... C++ 11 要求我有我的可执行文件中定义的所有三种存储方法吗?也就是说,GCC 4.8.4让我逃避了一些本不应该的东西?或者这是我需要切换的一些GCC 5.4选项,以允许我从类中删除未使用的静态成员?
如果答案是“你必须定义它们,不管”,那么我会定义它们,或者设计一些其他方式来允许。如果答案是“应该没问题”,而且也没有选择,我可以在命令行设置,使GCC 5.4的做吧,然后我会采取下一步行动,并在NXP论坛报告错误。谢谢。
为什么不暴露'CreateInstance'函数,而不是要求用户代码来定义(一些)功能? http://coliru.stacked-crooked.com/a/5e84854041391a9c – aschepler
@aschepler - 我喜欢这种模式。但是说我有一个板对象,并且我想通过调用'GetInstance(2)'来初始化'Uart&'引用。我如何确保'CreateInstance(2)'将在该对象引用被初始化之前被调用一段时间? –