const 字段的复杂初始化
考虑这样一个类:
class MyReferenceClass
{
public:
MyReferenceClass();
const double ImportantConstant1;
const double ImportantConstant2;
const double ImportantConstant3;
private:
void ComputeImportantConstants(double *out_const1, double *out_const2, double *out_const3);
}
有一个例程 (ComputeImportantConstants) 在运行时计算三个常量。假设计算相当复杂,并且本质上会同时产生所有三个值。此外,结果取决于构建配置,因此不能选择对结果进行硬编码。
是否有一种明智的方法将这些计算值存储在类的相应 const double 字段中?
如果没有,你能建议一种更自然的方式在 C++ 中声明这样的类吗?
在 C# 中,我将在这里使用带有静态构造函数的静态类,但这在 C++ 中不是一个选项。我也考虑过将ImportantConstant1..3设为非常量字段或函数调用,但两者似乎都较差。
我发现初始化 const 字段的唯一方法是 使用初始化列表,但似乎不可能在这样的列表中传递多输出计算的结果。
Consider a class like this one:
class MyReferenceClass
{
public:
MyReferenceClass();
const double ImportantConstant1;
const double ImportantConstant2;
const double ImportantConstant3;
private:
void ComputeImportantConstants(double *out_const1, double *out_const2, double *out_const3);
}
There is a routine (ComputeImportantConstants) that computes three constants at runtime. Suppose the computation is fairly complex, and inherently produces all three values at once. Moreover, the results depend on build configuration, so hardcoding the results isn't an option.
Is there a sensible way to store these computed values in the corresponding const double fields of the class?
If not, can you suggest a more natural way to declare such a class in C++?
In C# I would use a static class with a static constructor here, but that isn't an option in C++. I have also considered making ImportantConstant1..3 either non-const fields or function calls, but both seem inferior.
The only way to initialize const fields that I found is to use initializer lists, but it doesn't seem possible to pass the results of a multi-output computation in such a list.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
为什么你不能这样做:
像那样,让计算函数变成工厂函数?
Why can't you do:
Like that and have the calculate function turn into a factory function?
首先 - 你可以做坏事:在 ComputeImportantConstants() 中丢弃 const 并将值放在那里。但不要这样做,因为这样你就对编译器撒了谎,它会试图找到最恶劣的方式来偿还。
第二:
做这样的事情:
您仍然可以通过使其成为某种单例左右来改进此类(因为您希望计算只完成一次)。
first - you can do evil: cast away const in ComputeImportantConstants() and place the values there. Don't do it though, because then you lie to the compiler and it'll try to find the nastiest way to pay back.
second:
do something like this:
you still can improve this class by making it some kind of singleton or so (since you want the computation to be done only once).
您可以将 const 字段移至基类,然后传递包装类来初始化它们:
You could move the
const
fields to a base class, and then pass an wrapper class to initialize them:这是真的;但是,您可以初始化单个成员 - 这是一个常量结构。见下文。
我不认为 getter 函数会较差。编译器很可能会内联它们。考虑一下:
由于
m_constants
及其所有字段都是常量,因此其他成员方法无法更改这些值 - 只能在您在问题中概述的代码中更改。初始化可以是之所以在这里使用,是因为我们初始化了一个值:一个结构体。
对常量的访问(很可能)与以前一样高效:考虑到 getter 的大小,建议内联函数,并且编译器很可能会这样做。
That's true; however, you could initialize a single member - which is a struct of constants. See below.
I don't think that getter functions would be inferior. The compiler would most likely inline them. Consider this:
Since
m_constants
as well as all its fields are constant, the values cannot be changed by other member methods - just in the code you sketched in your question. An initialize can beused here since we initialize a single value: a struct.
Access to the constants is (most likely) to be as efficient as before: the suggest to inline the functions and the compiler is quite likely to do so given how small the getters are.
要修改已接受的答案,请注意,从 C++11 开始,您可以执行非常巧妙的技巧。例如,您的原始问题可以通过 lambda 和构造委托来解决,如下所示:
或者更好的是,如果可能的话,将初始化代码从computeImportantConstants 移动到构造函数中的 lambda 中。
实际上,使用 lambda 调用来初始化常量成员是一个非常方便的技巧,特别是因为您还可以将参数绑定和/或传递给 lambda。使用构造委托有助于简化成员的初始化,这些成员最好一起初始化或可能相互依赖。
但是,在使用构造委托时要格外小心,因为函数调用(或构造函数调用)的函数参数的初始化顺序是未定义的,并且最终可能会以错误的顺序或可能导致以下情况的方式初始化事物:如果出现故障或引发异常,则资源泄漏。
To amend the accepted answer, please note, that as of C++11 you can do very neat tricks. For example, your original problem can be solved with a lambda and construction delegation as follows:
Or better yet, move the initialization code from
computeImportantConstants
into the lambda in the constructor, if possible.In practice, using lambda calls to initialize constant members is a very handy trick, especially because you can also bind and/or pass arguments to the lambda. And using construction delegation helps to ease initialization of members which can best be initialized together or might depend on each another.
However, exercise extra caution when using construction delegation, because the initialization order of function arguments for a function call (or a constructor call) is undefined, and one might end up initializing things in an incorrect order, or in a manner which could lead to resource leaks if something fails or throws an exception.
只需将事物分为易于初始化的部分和复杂的部分,并通过复制构造函数初始化复杂的部分:
Just split up the thing into the part that is simple to initialize and the complex part, and initialize the complex part via copy constructor:
类似这样的事情怎么样:
What about something like that:
上面的答案似乎都没有关注一个细节:这里提到了
static
,因此这些常量似乎独立于类的实际实例。换句话说:这些是全局常量。正如您所猜测的,const 关键字的存在在这里很重要,因为编译器将应用优化。
无论如何,我们的想法是使用辅助结构。
当然,在真实的程序中,我鼓励您将常量实际包装在某种接口后面,以这种方式公开它们确实是不好的做法,因为这使得更改它们(使用另一种类型)非常困难。
另请注意,您不需要输出参数的指针,普通引用则需要。
None of the answer above seemed to pay attention to a detail:
static
is mentioned here, so these constants seem to be independent of the actual instance of the class.In other words: those are global constants. As you guessed, the presence of the
const
keyword is important here, because of the optimizations the compiler will apply.Anyway, the idea is to use a helper structure.
Of course, in a real program, i would encourage you to actually wrap the constants behind some kind of interface, it's really bad practice to expose them this way, because it makes changing them (using another type) very difficult.
Also note that you don't need pointers for output parameters, plain references do.