【问题标题】:Template object declaration and initialization: manually call template constructor to bypass standard constructors calls order模板对象声明和初始化:手动调用模板构造函数绕过标准构造函数调用顺序
【发布时间】:2013-11-11 18:16:57
【问题描述】:

首先,如果我的术语有些不准确或不正确,我深表歉意:这是 C++ 的一个方面,我没有过多处理。

我正在为一个 iOS 项目使用 Google 的 sparsehash 哈希表实现(我正在处理共享库,因为它针对越狱设备):特别是,我正在使用 dense_hash_map:我需要该模板的对象(命名正确吗?)作为结构的成员,该结构在项目中的多个文件之间共享。

我需要在__attribute__((constructor)) 函数(共享库的构造函数)中访问那个“对象”(即结构内的dense_hash_map)。问题显然是,模板的“自动构造函数”在 dyld 处理共享库的构造函数之后被调用:我只能在手动调用构造函数时使用dense_hash_map 对象就像在 __attribute__((constructor)) 函数中的 mymap = dense_hash_map<const char*, int, hash<const char*>, eqstr>(); 一样。

但是,模板构造函数以这种方式被调用了两次,一次是手动调用,一次是根据 C++ 自动构造函数调用。如何在不改变模板本身设计的情况下避免这种情况?

其他奇怪的是:

  • 如果 dense_hash_map 对象在该函数内被声明为局部变量,则一切正常。
  • 此问题仅发生在共享库中:简单的独立程序不受此问题的影响。

所以,最后我想问的是:

  1. 如何声明模板对象并强制其手动初始化,基本上没有自动调用模板构造函数?
  2. 模板构造函数在局部/全局变量情况下的处理方式有何不同?

如果我没有使用正确的术语,请告诉我。我希望有人可以阐明这一点,在此先感谢!

更新:不同情况的示例代码。

// global dense_hash_map
dense_hash_map<const char*, int, hash<const char*>, eqstr> months;

__attribute__((constructor)) static void my_constructor_0()
{
    /*
     actually crashes because you need to call set_empty_key()
     right after the template constructor, which has not been called
     yet, at this point
     */
    months.set_empty_key(NULL);
    months["january"] = 31;
}



__attribute__((constructor)) static void my_constructor_1()
{
    // local dense_hash_map
    dense_hash_map<const char*, int, hash<const char*>, eqstr> months;

    /*
     doesn't crash, works as it should and the map is being initialized
     correctly
     */

    months.set_empty_key(NULL);
    months["january"] = 31;
}


// global dense_hash_map
dense_hash_map<const char*, int, hash<const char*>, eqstr> months;

__attribute__((constructor)) static void my_constructor_2()
{
    /*
     works as it should but if you add a log to the template constructor,
     you see it being initialized twice: the first one is the manual call
     and the second one is the automatic constructor
     */

    months = dense_hash_map<const char*, int, hash<const char*>, eqstr>();
    months.set_empty_key(NULL);
    months["january"] = 31;
}

【问题讨论】:

  • 你能分享无法编译的示例代码吗?
  • 我遇到的唯一可能与编译有关的问题是如何声明模板对象,而无需通过其构造函数对其进行初始化。我没有任何不能编译的代码。

标签: c++ templates constructor


【解决方案1】:

阅读C++: When (and how) are C++ Global Static Constructors Called?http://www.parashift.com/c++-faq-lite/static-init-order.html

似乎有一种叫做“静态初始化顺序惨败”的东西。不同编译的初始化顺序不同,因此不确定变量在使用前何时初始化。

http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html 的建议是创建一个包含静态变量的函数,以确保在首次使用之前进行初始化。

据此,并使用此问题中的 dense_hash_map,这是防止此问题的代码 sn-p:

typedef dense_hash_map<const char*, int, hash<const char*>, eqstr> hashtable;

//singleton function
hashtable *month_singleton() {
    static hashtable *months = NULL;
    //initialization, happens on first run
    if (months == NULL) {
        months = new hashtable();
        months.set_empty_key(NULL);
    }
    return months;
}

__attribute__((constructor)) static void monthly_constructor()
{
    months_singleton()["january"] = 31;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    相关资源
    最近更新 更多