C++:在堆栈上使用未初始化的数据

3
我想创建一个适配器,它使用函数签名为void convert(void* input, T* out, int* ok)的函数(其中T被重载为任何类型),而ok表示是否发生错误(这些函数已提供,我无法更改其内容)。以下是模板内部功能的一部分:
template<typename T>
T convert_adapter(void* input){
    T result;
    int ok = 1;
    convert(input, &result, &ok);
    if (!ok)
        throw Exception("error during conversion");
    return result;
}

对于像 int 和简单结构体这样的类型,这样做已经足够好了,但是对于没有默认构造函数的更复杂的类和结构体而言会失败,因为result不能在第一行进行默认初始化。事实上,如果convert中发生错误,我不使用result,而如果没有发生错误,convert将自己分配一个初始化值给result (*out = {...}),所以我从来不需要初始化result

如何向convert提供适当类型的未初始化数据指针?我知道我可以用char[sizeof(T)]来做到这一点,但我想知道是否有更优雅的解决方案。

编辑:我现在意识到这个问题与C++的一些基本概念相违背,我将尝试与convert的提供者交谈,寻找解决方案。我将保留此问题,以备后人参考。


“convert” 不是初始化,而是赋值。如果使用 char[sizeof(T)] 而不将 “convert” 更改为初始化而不是赋值,则结果不会很好。 - StoryTeller - Unslander Monica
你正在做的几乎肯定是未定义行为。这种从内存中进行的类型转换是对对象进行X射线检查,甚至可能无法与POD类型一起使用。它被称为type punning,并且违反了C++的strict aliasing规则 - Fantastic Mr Fox
1
convert() 对于不支持默认构造函数的类型有哪些现有用例?例如,如果调用 convert(input, &some_foo, int *ok),其中 some_foo 是类型为 Foo 的变量,那么 some_foo 如何初始化?有了这些信息,您可能能够指定适当的 convert_adapter<Foo>() 特化。如果没有这些信息,任何人都只能猜测。 - Peter
@Peter,例如,一个接受两个整数的类Pointconvert可以执行以下操作:*out = {3,4}; - bentheiii
1
你被允许阅读convert的源代码吗?如果是这样,请发布它。如果不是,您需要阅读文档。如果convert的作者打算将其与这些类一起使用,则会在文档中提供指南。绝对不可能编写适用于所有类的convert,因此作者需要选择一些固定的类型convert能够处理,并在文档中进行描述。 - n. m.
显示剩余2条评论
2个回答

1

(*out = {...})这并不是初始化。

赋值和初始化并不相同。在您试图优化的情况下,对未初始化的数据进行赋值是未定义行为。

您可以使用放置new来进行初始化,但由于无法更改convert的主体,因此不允许这样做。


是的,但是将已初始化的值分配给相同类型的变量会被视为初始化,不是吗?除非该类型重载了赋值运算符。 - bentheiii
好的。我希望有一种方法可以在不破坏的情况下进行分配,或者在不初始化的情况下进行声明,但我看到我以错误的心态来解决这个问题了。 - bentheiii
@benth 不,它不会。默认情况下进行的是逐元素赋值。如果递归地没有赋值重载,则您的数据可能是pod,并且在第一种情况下构造它可能是免费的。请参阅三(五(零))法则。 - Yakk - Adam Nevraumont
@bentheiii 你可以构造内存地址,并在堆栈上为没有对象的对象创建内存。但是你说你不能更改执行赋值的函数,所以你很不幸:它会分配,并且分配要求已经有一个对象存在。 - Yakk - Adam Nevraumont

0

既然result已经被返回了,为什么不改变convert_adapter的签名呢?你可以将其作为输出参数而不是返回值:

template<typename T>
convert_adapter(void* input, T* result){
    int ok = 1;
    convert(input, result, &ok);
    if (!ok)
        throw Exception("error during conversion");
    return;
}

这样,您可以在convert_adapter之外初始化result,从而可以使用非默认构造函数。无论如何,在调用convert_adapter时都必须存在类型为T的变量,因为您可能想将结果分配给某些东西。
T result(non,default,contructor,parameter,values);
//result = convert_adapter(input); // old
convert_adapter(input, &result); // new

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接