0

我想在 jniOnLoad 方法中缓存 jni 类 ID。最终,此过程将按如下方式进行:

for each class name in my list, call env->FindClass

作为开发人员,我宁愿不必将类名添加到位于我的类之外的中央静态向量中。相反,我想在我正在编辑的文件中继续注册这个集合。例如

JNIUtility.h
void appendClassName(std::string &className); // append name to mClassNameVector

JNIUtility.cpp
vector<string> mClassNameVector;
void jniOnLoad()
  // iterate over all items in mClassNameVector and obtain the class id's

...

NewClass.cpp
  appendClassName("com/my/path/NewClass");

我的问题是,我可以在静态编译时 push_back 到 mClassNameVector 吗?如果是这样,怎么做?

4

1 回答 1

2

您无法std::vector<std::string>在编译或链接时构建您的。但是,您可以在静态初始化期间构建它。您可以让全局对象的构造函数在另一个全局对象上调用某些东西。例如,您可以执行以下操作:

std::vector<std::string> mClassNameVector;
static bool dummy = []{ mClassNameVector.push_back("some string"); return true; };

但是,将注册移至不同的翻译单元后,会出现两个问题:

  1. 全局对象的构建顺序在翻译单元中是未定义的(在翻译单元内它只是从上到下)。为了避免调用push_back()尚未构造的向量时出现问题,您只需将对象包装到一个函数中:

    std::vector<std::string>& mClassNameVector() {
        static std::vector<std::string> rc;
        return rc;
    }
    static bool dummy = []{ mClassNameVector().push_back("some string"); return true; };
    

    由于static函数局部变量是在第一次调用函数时构造的,所以这种方法保证了在mClassNameVector()访问它之前就构造了它。请注意,该构造在 C++03 中不是线程安全的。但是,它在 C++ 中是线程安全的(截至 2011 年修订版):只有一个线程会初始化rc. rc在构造过程中进入函数的任何其他线程都将阻塞。

  2. 另一个潜在的问题是您的类可能不会被任何地方引用,因此,包含注册变量的文件可能不会包含在最终的可执行文件中。尤其是在库中实现类并希望它们注册自己时往往会失败。此外,当目标文件以将不同实体放入单独部分的方式构建时,注册变量有可能未链接到可执行文件中。但是,通常它会显式链接目标文件。除非每个文件都包含从某处引用的符号,否则将目标文件放入库中通常不起作用。
于 2013-11-14T01:04:37.643 回答