是否可以延迟 C++ 中 const 变量的初始化,例如 Java 的 "blank final" 功能?
Is it possible to defer initialization of a const variable in C++, like Java's "blank final" feature?
在Java中我们可以声明一个blank final
变量,稍后再初始化。编译器将确保初始化恰好发生一次——初始化失败或双重初始化都是编译时错误。例如:
public int bar() {
return 66;
}
public void foo() {
final int x; // declare the variable
...
x = bar(); // initialization only once
}
在Java中,编译器可以保证x
在第一次赋值之前绝对不会在任何代码路径上赋值,并且可以保证绝对不会在任何代码路径上进行第二次赋值代码路径。 (有关详细信息,请参阅 Chapter 16, Definite Assignment, of the Java Language Specification。)
我们如何在 C++ 中实现类似的行为?是否可以声明一个变量 const
但推迟其初始化? (不丢弃 const
说明符。)
除非定义了常量,否则无法对其进行初始化。您必须找到一种方法来了解其定义的价值。如果 x
的值难以确定,请考虑使用像
这样的函数的结果
const int x = calc_x();
或像
这样的闭包
const int x = []() { /* code to calculate x's value */ }();
const
ness 是对象类型的一部分,对象类型在任何情况下都不能更改,因此 x
是 const
并且您无法对其进行初始化稍后或 x
根本不是 const
。
可以设计一个包装器 class
来模拟这个,但你最多只能得到一个 运行 时间错误。
请注意,似乎有 const_cast
形式的解决方案,但假设所讨论的对象实际上不是 const
。在 const int x
的情况下,无法在初始化后合法地更改它的值。
C++ 没有针对此的内置功能。不过,您可以自己构建它。您可以创建一个 class 来保存您想要的类型的对象的存储空间,并且可以为此重载赋值运算符,以便它只能被调用和初始化一次。那看起来像
template<typename T>
class once
{
private:
std::aligned_storage_t<sizeof(T), alignof(T)> data;
T* ptr = nullptr;
public:
once() = default;
~once()
{
if(ptr) // it is initialized so call the destructor
ptr->~T();
// optionally you can add
// throw("a once<T> must be initialized once");
// this can help to enforce that the object is actually initialized as you'll get a runtime exception in code that does not do so
}
template<typename U>
once& operator =(U&& value)
{
if (!ptr) // it is not initialized so call constructor
{
ptr = new(&data) T(std::forward<U>(value));
}
else
throw ("can only assign to a once<T> once.");
return *this;
}
operator const T&()
{
return *ptr;
}
};
然后你会像
一样使用它
int main()
{
once<int> foo;
if (1 < -1)
foo = 21;
else
foo = 42;
std::cout << foo;
//foo = 23; // uncomment this to get an exception.
}
在Java中我们可以声明一个blank final
变量,稍后再初始化。编译器将确保初始化恰好发生一次——初始化失败或双重初始化都是编译时错误。例如:
public int bar() {
return 66;
}
public void foo() {
final int x; // declare the variable
...
x = bar(); // initialization only once
}
在Java中,编译器可以保证x
在第一次赋值之前绝对不会在任何代码路径上赋值,并且可以保证绝对不会在任何代码路径上进行第二次赋值代码路径。 (有关详细信息,请参阅 Chapter 16, Definite Assignment, of the Java Language Specification。)
我们如何在 C++ 中实现类似的行为?是否可以声明一个变量 const
但推迟其初始化? (不丢弃 const
说明符。)
除非定义了常量,否则无法对其进行初始化。您必须找到一种方法来了解其定义的价值。如果 x
的值难以确定,请考虑使用像
const int x = calc_x();
或像
这样的闭包const int x = []() { /* code to calculate x's value */ }();
const
ness 是对象类型的一部分,对象类型在任何情况下都不能更改,因此 x
是 const
并且您无法对其进行初始化稍后或 x
根本不是 const
。
可以设计一个包装器 class
来模拟这个,但你最多只能得到一个 运行 时间错误。
请注意,似乎有 const_cast
形式的解决方案,但假设所讨论的对象实际上不是 const
。在 const int x
的情况下,无法在初始化后合法地更改它的值。
C++ 没有针对此的内置功能。不过,您可以自己构建它。您可以创建一个 class 来保存您想要的类型的对象的存储空间,并且可以为此重载赋值运算符,以便它只能被调用和初始化一次。那看起来像
template<typename T>
class once
{
private:
std::aligned_storage_t<sizeof(T), alignof(T)> data;
T* ptr = nullptr;
public:
once() = default;
~once()
{
if(ptr) // it is initialized so call the destructor
ptr->~T();
// optionally you can add
// throw("a once<T> must be initialized once");
// this can help to enforce that the object is actually initialized as you'll get a runtime exception in code that does not do so
}
template<typename U>
once& operator =(U&& value)
{
if (!ptr) // it is not initialized so call constructor
{
ptr = new(&data) T(std::forward<U>(value));
}
else
throw ("can only assign to a once<T> once.");
return *this;
}
operator const T&()
{
return *ptr;
}
};
然后你会像
一样使用它int main()
{
once<int> foo;
if (1 < -1)
foo = 21;
else
foo = 42;
std::cout << foo;
//foo = 23; // uncomment this to get an exception.
}