所以,我遇到了一個問題,我不確定它是語言問題還是編譯器/ 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)'將在該對象引用被初始化之前被調用一段時間? –