- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
所以,我遇到了一个问题,我不确定这是语言问题还是编译器/GCC 问题。
TL;DR - 我是否需要在类中定义所有静态方法,即使这些静态方法从未被调用应用程序(即无论如何都可以被链接器合法删除)?
我有一个库类,它为微 Controller 中的 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++ 模块中,因为,呃。)这是 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 并编译和链接 没有错误。
但 NXP 已弃用另一个工具链 (MCUXpresso 10.0) 的 KDS,它使用 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()'
我不确定为什么链接器会关心 GetStorage()
UART1 和 UART3 的方法没有定义,因为我没有调用 GetInstance()
对于我的应用程序中的 UART1 或 UART3,因此从不调用相应的 GetStorage()
方法之一。
我的问题是……C++11 要求我在我的可执行文件中定义所有三种存储方法吗?也就是说,GCC 4.8.4 是否让我摆脱了一些我不应该做的事情?或者这是我需要切换的某个 GCC 5.4 选项,以允许我从类中删除未使用的静态成员?
如果答案是“无论如何你都必须定义它们”,那么我会定义它们,或者也许设计一些其他方式来允许。如果答案是“那应该没问题”,并且没有我可以在命令行上设置的选项来使 GCC 5.4 执行此操作,那么我将采取下一步并在 NXP 论坛中报告错误。谢谢。
最佳答案
TL;DR - Am I required to define all static methods within a class, even if those static methods are never called by the application
您可能需要定义此类静态方法,即使它们从未被应用程序调用。
但是,一般来说,如果这些函数不是 odr-used,您可能不需要这样做(一个定义规则)。对于静态成员函数,这等同于
A function whose name appears as a potentially-evaluated expression
区别很微妙。我希望这证明了这一点:
if(false)
function();
function
永远不会被调用,但会出现在一个可能被评估的表达式中,因此是 odr-used,因此必须被定义。
My question here is... does C++11 require me to have all three storage methods defined in my executable?
是的。它们都出现在潜在求值表达式中,因此是 ODR 使用的,因此必须定义。
I was developing an earlier application using ... GCC 4.8.4 and compiles and links with no errors.
Odr 违规具有未定义的行为,这解释了为什么您没有在其他工具链中收到错误/警告。
关于c++ - 是否必须定义所有静态类方法,即使未使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46207999/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!