拥有一个“constify”是否有意义? C++ 中的操作?
在 C/C++
中使用“constify
”操作来生成变量 const
是否有意义?
这是一个它可能有用的示例,显然我们不想在第一行中将其声明为 const:
std::vector<int> v;
v.push_back(5);
constify v; // now it's const
目前,如果没有这种可能性,您必须引入另一个变量来获得相同的效果:
std::vector<int> v0;
v0.push_back(5);
const std::vector<int>& v = v0;
这更令人困惑,因为它在范围中添加了一个新名称,并且您需要将其作为引用以避免复制整个向量(或使用 swap
?)。
Would it make sense to have a "constify
" operation in C/C++
that makes a variable const
?
Here is an example where it could be useful, where obviously we don't want to declare it const
yet in the first line:
std::vector<int> v;
v.push_back(5);
constify v; // now it's const
Currently, without such a possibility, you'd have to introduce another variable to get the same effect:
std::vector<int> v0;
v0.push_back(5);
const std::vector<int>& v = v0;
That's more confusing since it adds a new name into the scope and you need to make it a reference to avoid copying the whole vector (or use swap
?).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
坦率地说,我发现变量是否为 const 比可以更改更容易混淆。
详细说明一下:您通常想要这样做的原因是因为您无法按照您想要的方式初始化
const
变量。std::vector
就是一个很好的例子。好吧,这一次,下一个标准引入了一个通用初始化语法,使这成为可能:但是,即使手头没有 C++1x 的东西,甚至使用不允许此初始化语法的类型,您始终可以创建一个辅助函数来执行你想要什么:
或者,如果你想要更奇特:
请注意
&
。复制函数调用的结果是没有意义的,因为将右值绑定到 const 引用会延长其生命周期,直到引用生命周期结束。当然,使用支持 C++1x 移动语义的编译器重新编译将使此类优化几乎没有必要。但是将 rvlaue 绑定到
const
引用可能仍然比移动向量更快,并且不太可能慢。使用 C++1x,您还可以创建 lambda 函数来快速执行此操作。 C++ 提供了极其庞大的工具库。 IME,无论你多么努力地思考,其他人都应该想出另一个想法来做同样的事情。而且往往比你的更好。
然而,无论如何,IME 这个问题通常只是由于代码过多而函数太少造成的。然后它不仅适用于常量,还适用于类似的特征 - 比如引用所指的内容。
一个经典的方法是使用多个可能的流之一。相反,
只需将问题分为 1)弄清楚从哪里读取和 2)实际读取:
我还没有看到一个变量的真实示例,该变量不像它应有的那样恒定,而且不可能'不能通过关注点分离来解决。
Frankly, I find it less confusing if a variable is either
const
or not, than if this can change.To elaborate a bit on this: The reason you usually want to do this is because you cannot initialize a
const
variable the way you want to.std::vector
is a good example of this. Well, for once, the next standard introduces a universal initialization syntax that makes this possible:However, even without C++1x' stuff at hand, and even with types that disallow this initialization syntax, you can always create a helper function to do what you want:
or, if you want to be fancy:
Note the
&
. There's no point in copying the result of the function call, since binding an rvalue to aconst
reference extends its lifetime until the end of the reference's lifetime.Of course, recompiling with a compiler that supports C++1x' move semantics will render such optimizations pretty much needless. But binding an rvlaue to a
const
reference might still be faster than moving a vector and is unlikely to be slower.With C++1x, you might also create lambda functions doing this one the fly. C++ just provides an incredibly huge arsenal of tools. IME, no matter how hard you have thought, someone else ought to come up with yet another idea to do the same thing. And often a better one than yours.
However, IME this problem usually only comes with too much code in too few functions anyway. And then it doesn't only apply to constness, but also to similar traits - like what a reference refers to.
A classic is the use-one-of-several-possible-streams. Instead of this
just split the concerns into 1) figuring out where to read from and 2) the actual reading:
I have yet to see a real-world example of a variable that wasn't as constant as it could have been which couldn't be fixed by separating of concerns.
您基本上是在尝试重现构造函数的效果 - 即 const 仅在构造函数完成后应用(并且仅在调用 dtor 之前)。因此,您需要的是另一个类来包装您的向量并在构造函数中对其进行初始化。一旦构造函数完成并返回,实例就变成 const(当然,假设它被定义为 const)。
C++0x 将大大改善对这种包装的要求。您将能够使用向量的大括号初始值设定项在一次操作中创建/初始化向量。其他类型将(至少可能)支持用户定义的初始值设定项来完成大致相同的事情。
You're basically trying to reproduce the effect of a constructor -- i.e.,
const
applies only after the constructor completes (and only until the dtor is invoked). As such, what you need is another class that wraps your vector and initializes it in the ctor. Once the ctor completes and returns, the instance becomesconst
(assuming, of course, that it was defined to beconst
).C++0x will ameliorate the requirement for wrapping like this considerably. You'll be able to use brace initializers for vectors to create/initialize the vector in one operation. Other types will (at least potentially) support user-defined initializers to accomplish roughly the same thing.
C++ 是静态类型的。对我来说,引入这样的操作将违反这一范式,并且会引起很多混乱。
C++ is statically typed. To me, introducing such an operation would be a violation of this paradigma and would cause much confusion.
这是使用函数的好时机
This is a great time to use a function
我假设您谈论的是比初始化向量(在 C++0x 中解决)更通用的东西,并且仅使用向量作为示例。
我宁愿看到它通过某种本地函数完成:(
我可能会弄乱 C++0x 的匿名函数语法)。我可以很自然地将其读为:“根据此处描述的例程准备常量向量”。只是括号的数量稍微让我烦恼。
我可以看到,在 C++0x 对程序员来说变得更加自然之后,这段代码可能会成为 C++ 习惯用法。
(根据德曼的建议进行编辑)
I assume you're talking about something more generic than only initializing vectors (which is solved in C++0x), and use vectors only as an example.
I'd rather see it done through some kind of local functions:
(I could mess anonymous function syntax of C++0x). This I can read quite naturally as: "prepare a const vector according to routine described here". Only amount of parentheses bother me slightly.
I can see how this code might become a C++ idiom after C++0x becomes more natural to programmers.
(edited after dehmann's suggestion)
我也想过这个问题。但是,恕我直言,它会造成很多混乱,这将超过它的好处。想想看,C++ 中常量的整个概念已经够令人困惑的了。
您的想法可以归结为“如何在变量初始化后使其变为只读?”。您可以通过将变量设置为类的私有成员来获得相同的效果,该变量在构造函数中初始化,并为其提供 getter 但不提供 setter。
I have thought about this too. But, IMHO, it will create a lot of confusion, which will outweigh its benefits. Come to think of it, the whole notion of constness in C++ is already confusing enough.
Your idea boils down to "How can I make a variable read-only after it has been initialized?". You can get the same effect by making your variable a private member of a class, which is initialized in the constructor, and for which you provide a getter but no setter.
已经提到过,C++0x 使用大括号初始化器在某种程度上解决了这个问题:
尽管这只允许初始化,并且不允许在构造函数运行后调用非 const 成员函数。 可以定义一个宏
constify
如下:可以像这样使用:
这通过设置一个执行
for
循环来实现以下语句或块仅一次,且 constified 变量位于循环体的本地。请注意局部i
之前辅助变量i_const
的声明:语句int const& i(i)
将i
初始化为自身,即未初始化的值,我们希望(i)
而是引用之前声明的i
,因此需要额外的级别。如果您可以利用 C++0x 功能,则
decltype
关键字会派上用场,它允许您在调用constify
时省略类型:这使您可以简单地编写:
无论变量最初是否声明为 const,两个版本都可以工作。所以,是的,与您正在寻找的东西非常相似的东西确实是可能的,但可能完全不值得。
It's already been mentioned that C++0x solves this somewhat with brace-initialisers:
Though this only allows for initialisation, and does not allow, for instance, invoking non-
const
member functions after the constructor has run. It is possible to define a macroconstify
as follows:Which can be used like so:
This works by setting up a
for
loop that executes the following statement or block only once, with the constified variable local to the loop body. Note the declaration of helper variablei_const
before the locali
: the statementint const& i(i)
initialisesi
to itself—that is, to an uninitialised value—and we want the(i)
to refer instead to the previously declaredi
, so an extra level is needed.If you can make use of C++0x features, the
decltype
keyword comes in handy, allowing you to omit the type from invocations ofconstify
:Which lets you write, simply:
Both versions work whether the variable is initially declared
const
or not. So, yes, something very like what you were looking for is indeed possible, but probably altogether not worth it.目前,编译器知道是否为 const,因此编译器不会接受尝试更改 const 变量的程序。
如果您想创建一个 constify 运算符,则必须将其设置为变量的属性(没有进一步的关键字,每个变量),以便它可以在运行时更改。当然,每当程序尝试更改(当前)const 变量时,您都必须抛出异常,这实际上意味着对每个变量的每次写访问都必须检查 const > 财产第一。
所有这些都违背了 C++ 和所有其他静态类型语言的哲学。它还破坏了与现有库的二进制兼容性。
Currently,
const
or not is something that the compiler knows, so the compiler won't accept a program that tries to change aconst
variable.If you wanted to make a
constify
operator, you would have to make this a property of the variable (without further keywords, of every variable) so it can change at runtime. And of course you would have to throw an exception whenever a program tries to change a (currently)const
variable, which effectively means that every write access to every variable must check theconst
property first.All this goes against the philosophy of C++ and every other statically typed language. And it breaks binary compatibility with existing libs, too.
考虑以下几点:
foo 中的变量
v
是否已被构造?它与 bar 中的test
变量相同。因此,test.clear()
调用应该是无效的。我认为你真正的意思是名称是“constified”,而不是变量。指定和实现实际上很简单:
constify x;
是一个名为 x 的 const 引用的声明,它与它隐藏的变量 x 具有相同的基类型。它遵循通常的作用域规则,只是它可以在与之前的x
声明相同的作用域中定义。Consider the following bit:
Is the variable
v
in foo constified? It is the same variable astest
in bar. Thus, thetest.clear()
call should be invalid. I think that what you really meant is that the name is "constified", not the variable.It would be actually trivial to specify and implement:
constify x;
is a declaration of a const reference named x, which has the same base type as the variable x it hides. It follows the usual scope rules, except that it may be defined in the same scope as the previousx
declaration.您可以将向量包装在类中,声明包装的向量可变,然后创建包装器的 const 实例。包装类可以更改向量,但外部调用者看到的是 const 对象
You could wrap the vector in a class , declare the wrapped vector mutable, and then make a const instance of the wrapper. The wrapping class can change the vector but external callers see a const object