[英]How to pass a pointer to an integer without a temporary variable?
在我过去的许多语言中,有一种方法可以传递一个整数常量/文字作为参考,以避免不必要地创建极其短暂的变量到函数。 一个很好的例子是setsockopt调用的重用变量。 例如
int reuseVal = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuseVal, sizeof (reuseVal));
某些语言允许您执行以下操作
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, %ref(1), sizeof (int));
C ++中是否有类似的方法?
C ++内置的东西没有你想要的东西,但你自己很容易构建一个(为了清晰起见,额外的日志记录):
template <typename T>
class holster
{
public:
using value_type = T;
template <typename... U>
holster(U&&... args)
: _val(std::forward<U>(args)...)
{
std::cout << "CTOR: holster" << std::endl;
}
~holster()
{
std::cout << "DTOR: holster" << std::endl;
}
value_type* ptr() { return &_val; }
private:
value_type _val;
};
这种类型的用法非常简单:
struct thing
{
thing()
{
std::cout << "CTOR: thing" << std::endl;
}
~thing()
{
std::cout << "DTOR: thing" << std::endl;
}
};
void foo(thing*)
{
std::cout << "in foo" << std::endl;
}
int main()
{
foo(holster<thing>().ptr());
return 0;
}
要扩展回原始示例:
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, holster<int>(1).ptr(), sizeof (int));
为什么这样做? C ++生命周期的一个鲜为人知的特性是,在函数持续时间内,为传递给函数而创建的任何临时函数都是生命周期延长的。 保证引用( holster::_val
)在foo
返回之前继续存在,并且在评估下一个完整表达式之前将被正确销毁(在本例中,在;
之前)。
§6.6.7/ 4 [class.temporary]
当实现引入具有非平凡构造函数的类的临时对象( [class.default.ctor] , [class.copy.ctor] )时,它应确保为临时对象调用构造函数。 类似地,析构函数应该用一个非平凡的析构函数( [class.dtor] )来调用。 临时对象作为评估全表达式( [intro.execution] )的最后一步被销毁,该表达式(词法上)包含创建它们的点。 即使该评估以抛出异常结束,也是如此。 销毁临时对象的值计算和副作用仅与完整表达相关联,而不与任何特定子表达相关联。
你不能直接这样做。 在C中你可以使用复合文字(例如(int []){ 1 }
),但这在C ++中不可用。
但是,您可以编写如下辅助函数:
template<typename T>
struct temp_holder {
T data;
explicit temp_holder(T x) : data(x) {}
T *ptr() { return &data; }
const T *ptr() const { return &data; }
};
template<typename T>
temp_holder<T> make_temporary(T x) {
temp_holder<T> tmp(x);
return tmp;
}
现在你可以这样做:
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, make_temporary(1).ptr(), sizeof (int));
在我使用g ++进行的测试中,在0以上的任何优化级别(即-O
, -O2
或-O3
)生成int reuseVal = 1
/ &reuseVal
版本的相同代码。
如果您想避免必须定义新的类型和函数,可以稍微滥用标准库:
#include <memory>
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, std::make_unique<int>(1).get(), sizeof (int));
这种方法的缺点是它经历了动态内存分配(加上(异常安全)释放),因此它可能比自定义类型慢(或者只是声明一个临时变量)。
setsockopt()
需要指向已分配变量的指针。 无论该变量是静态分配还是动态分配,都无关紧要,只要它具有可在运行时获得的可访问内存地址,然后取消引用以访问该地址处的数据即可。
您的原始代码正是如此。 它宣布,在自动内存分配的局部变量(即调用线程的调用堆栈),然后使用该地址的&
运营商来获取变量的内存地址,并将该地址setsockopt()
事情并没有那么简单。
您给出的其他答案只是同一主题的更复杂的变体 - 为变量赋值,然后获取该变量的地址。
为了节省声明基本类型变量并用数据填充它的ALREADY EXTREMELY MINIMAL开销,您可以使用在程序启动时初始化一次并在需要时重用的全局变量在编译时静态执行该操作,例如:
const int cReuseAddrOn = 1;
void setReuseAddrOn(int s)
{
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &cReuseAddrOn, sizeof (cReuseAddrOn));
}
我%ref(1)
其他语言中的%ref(1)
这样的东西可能与此类似地实现,创建对临时分配的变量或可重用的文字常量的引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.