构造一个对象以在其他地方按值返回
Constructing an object to return by value elsewhere
在一个用C++代码连接V8 JavaScript引擎的包装器中,我想调用一个按值传递对象的C++函数。该对象是根据JavaScript内部的数据自动构建的。
要调用的C++函数接受类型为T的对象,并使用模板生成适配器函数a,按值返回T。问题是适配器函数A需要调用一个JavaScript函数,将另一个C++函数B作为回调传递给它。T类型的对象是在函数B中构造的。它不能通过JavaScript返回给A,因为JavaScript不知道如何处理T类型的物体。
最简单的方法是在函数a中有一个T类型的局部变量。指向它的指针被赋予B,B为局部变量分配一个新值,a稍后返回,大致如此(关于如何将参数传递给callJavaScript和回调,省略了一些细节。实际上,T的构造函数和B函数可能会将任何数量的更复杂的类型作为参数):
C++代码:
T A() {
T data;
callJavaScript("someJavaScriptFunction", &B, &data);
return data;
}
void B(T *data, int importantValue) {
*data = T(importantValue);
}
JavaScript代码:
function someJavaScriptFunction(callback, dataRef) {
callback(dataRef, getImportantValueSomehow());
}
但是,如果类型T不支持赋值,甚至没有复制构造函数,该怎么办?有没有办法避免不必要的复制?我想把函数A内部的空白空间分配为一个局部变量:
typename std::aligned_storage<sizeof(T), alignof(T)>::type data;
然后,函数B可以使用placement new在该空间中构造对象,但我如何使用move语义从A返回结果对象?如何正确调用可能的析构函数?
我的最终想法是使用更多的模板技巧来为函数A中的类型T的构造函数分配参数空间,通过B中的指针设置它们,并最终在A中构造对象,但当callJavaScript返回时,如果某些参数中的数据超出范围,就会变得很糟糕。有解决方案吗?
EDIT:所有这些的目的是将JavaScript对象的内容获取到C++中。从C++中读取对象的属性需要使用字符串按名称查找。V8中的JIT编译函数可以更直接地访问对象的字段,并且在someJavaScriptFunction中读取对象的属性可以编译成简单的指针读取。然后,它可以用各种参数调用C++回调,这些参数从JavaScript值句柄转换为C++类型的速度相当快。
编辑2:简单的第一个想法是:
typename std::aligned_storage<sizeof(T), alignof(T)>::type data;
::new(&data) T(); // THIS LINE ACTUALLY PLACED IN ANOTHER FUNCTION
return(*reinterpret_cast<T *>(&data));
但是,我应该为数据中构建的对象T调用析构函数吗?何时调用,以及如何调用?这是一个库,向返回值的接收者添加代码实际上不是一个选项。
我不确定我是否完全理解您的问题,但似乎您不需要在函数中传递输出参数。
简单地让函数A返回一个值,就像你在问题中已经输入的那样,让B返回一个数值。
由于"命名返回值优化",不需要赋值运算符也不需要复制构造函数。也就是说,如果你的代码满足"NRVO"的要求,你就可以了:
T B(int importantValue) { return T{importantValue}; }
不需要赋值运算符,也不需要从T复制构造函数。然后,将callJavascript更改为不需要输出参数,而是返回一个值,然后这将在没有复制构造函数或赋值运算符的情况下工作:
T A() { A rv{callJavascript(&B)}; return rv; }
通常,要确保函数不需要输出参数,否则就要求类型具有复制构造函数和赋值运算符,或者违反类型系统。
顺便说一下,使callJavascript
成为一个以可调用为参数的模板。
我最终在a周围使用了一个包装器,该包装器处理调用placement new和a的析构函数。它允许库的用户提供任何类A,只要它有一个移动构造函数。工作测试的完整代码和关于它的讨论可以在一个更新的、公式化更好的问题中找到。放置新的、按值返回并安全地处理临时副本及其接受的答案。
- 按值 C++ 返回时进行双倍移动
- C++ 获取函数在常量引用中按值返回的结果
- 当 RVO 可以应用时,为什么要按shared_ptr而不是按值返回?
- 按值返回 std::array
- 为什么按值返回的对象与方法中的对象具有相同的地址?
- 为什么在按值返回时创建临时对象,而不是在按值传递给函数参数时创建临时对象
- 复制构造函数、按值传递和按值返回、链式操作、编译器
- 按值返回的函数无法按预期工作
- 如果函数按值传递并按值返回,将调用复制构造函数多少次
- 按值返回 ifstream 将编译
- C 按值返回与参考返回
- 此指针 - 按值返回 vs 按引用返回
- 如何按值返回`qObject'衍生的类
- 在对类对象的赋值进行链接时获取垃圾值,使用按值返回类对象的赋值运算符重载
- 在C++11中按值返回构造的对象时,避免复制构造函数调用
- 何时按值返回OK
- C++:按值返回并带有引用
- 按值返回堆栈上的变量是否优化为移动
- 按值返回指针不会移动对象
- 按值返回时强制 RVO/移动构造