例如,假设我有一个类:
class Foo
{
public:
std::string& Name()
{
m_maybe_modified = true;
return m_name;
}
const std::string& Name() const
{
return m_name;
}
protected:
std::string m_name;
bool m_maybe_modified;
};
Run Code Online (Sandbox Code Playgroud)
在代码中的其他地方,我有这样的事情:
Foo *a;
// Do stuff...
std::string name = a->Name(); // <-- chooses the non-const version
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么编译器在这种情况下会选择非const版本?
这是一个有点人为的例子,但我们试图解决的实际问题是如果对象已经改变则定期自动保存,并且指针必须是非const的,因为它可能在某些时候被更改.
我见过这样的方法:
void SomeClass::someMethod() const;
Run Code Online (Sandbox Code Playgroud)
这个const声明做了什么,它如何帮助优化程序?
编辑
我看到之前已经问过这个问题的第一部分...... 但是,它仍然没有回答第二部分:这将如何优化程序?
我正在讨论C并且对const使用指针有疑问.我理解以下代码:
const char *someArray
Run Code Online (Sandbox Code Playgroud)
这是定义指向char类型的指针,const修饰符意味着someArray不能更改存储的值.但是,以下是什么意思?
char * const array
Run Code Online (Sandbox Code Playgroud)
这是另一种指定参数的替代方法,该参数是指向名为"array" const且不能修改的数组的char指针吗?
最后,这个组合意味着什么:
const char * const s2
Run Code Online (Sandbox Code Playgroud)
作为参考,这些来自第7章中的Deitel C编程书,所有这些都用作传递给函数的参数.
在这一点上我确信我应该std::exception为我的所有异常抛出需求创建子类.现在我正在研究如何覆盖该what方法.
我面临的情况,如果字符串what返回是动态的,那将非常方便.例如,某些代码解析XML文件,并向错误消息添加位置或行号对我很有用.
我试图遵循Boost Exception处理指南.
我想知道的是什么:
what返回一个const char *,这意味着任何捕手都可能不会释放该字符串.所以我需要一些其他的地方来存储结果,但那会是哪里?(我需要线程安全.)
what还包括throw()其签名.虽然我可以阻止我what扔任何东西,但在我看来,这种方法真的不适合任何过于动态的东西.如果what不是正确的地方,那么我应该在哪里做这个呢?
从我到目前为止得到的答案看来,实现这一目标的唯一方法是将字符串存储在异常中.Boost指南建议不要这样做,这对我来说很困惑,因为std::runtime_error就是这样.
即使我使用的是C字符串,我也必须使用静态大小的缓冲区,或者进行内存管理也会失败.(我想知道这实际上是否是std::string复制构造函数中唯一可能出错的东西.这意味着我不会使用动态分配的C字符串获得任何东西.)
还有其他选择吗?
在Effective C++,第3项中,Scott Meyers建议重载operator*一个名为的类Rational:
class Rational { ... };
const Rational operator*(const Rational& lhs, const Rational& rhs);
Run Code Online (Sandbox Code Playgroud)
返回值被const限定的原因在下面的行中解释:如果不是const,程序员可以编写如下代码:
(a * b) = c;
Run Code Online (Sandbox Code Playgroud)
或者,更可能是:
if (a*b = c)
Run Code Online (Sandbox Code Playgroud)
很公平.现在我很困惑,因为我认为函数的返回值,这里是operator*,是一个rvalue,因此不能赋值.我认为它不是可转让的,因为如果我有:
int foo();
foo() += 3;
Run Code Online (Sandbox Code Playgroud)
那将无法编译invalid lvalue in assignment.为什么不在这里发生?有人可以对此有所了解吗?
编辑:我在Scott Meyers的那个项目上看到过很多其他线程,但是没有人解决我在这里暴露的rvalue问题.
我正在定义一个NSString用作NSError中的错误域,并且正在复制ASIHttpRequest在那里做的事情.
NSString* const FPServerAPIErrorDomain = @"FPServerAPIErrorDomain";
Run Code Online (Sandbox Code Playgroud)
我把const放在它自己的.h文件// FPServerAPICoordinatorConstants.h中
#ifndef FirePlayer_FPServerAPICoordinatorConstants_h
#define FirePlayer_FPServerAPICoordinatorConstants_h
NSString* const FPServerAPIErrorDomain = @"FPServerAPIErrorDomain";
#endif
Run Code Online (Sandbox Code Playgroud)
但是当我把它包含在一个以上的时候
SomeFile.m
#import "FPServerAPICoordinatorConstants.h"
SomeOtherFile.m
#import "FPServerAPICoordinatorConstants.h"
Run Code Online (Sandbox Code Playgroud)
我收到链接器错误'重复符号'
ld: duplicate symbol _FPServerAPIErrorDomain in SomeFile.o and ....SomeOtherFile.o for architecture armv7
Run Code Online (Sandbox Code Playgroud)
所以我将const更改为#define,它运行正常.
// FPServerAPICoordinatorConstants.h
#ifndef FirePlayer_FPServerAPICoordinatorConstants_h
#define FirePlayer_FPServerAPICoordinatorConstants_h
//THIS WAS TRIGGERING link errors
//NSString* const FPServerAPIErrorDomain = @"FPServerAPIErrorDomain";
//working OK
#define FPServerAPIErrorDomain @"FPServerAPIErrorDomain"
#endif
Run Code Online (Sandbox Code Playgroud)
但有没有办法让const在全球空间不要抛出"重复的符号"?
当C程序尝试将指针转换为指向数据(如或)的指针时,Microsoft Visual Studio中的C/C++编译器会发出警告C4090(即使这样的类型实际上不是指针).更奇怪的是,同一个编译器默默接受编译为C++的相同代码.constconst void **const char **void *const
什么是这种不一致的原因,以及为什么Visual Studio的(不像其他编译器)有隐含转换的指针指向一个问题const成void *?
我有一个C程序,其中在变量参数列表中传递的C字符串被读入一个数组(通过va_arg调用的循环).由于C字符串是类型const char *,跟踪它们的数组是类型const char **.这个带有const内容的字符串指针数组本身是动态分配的(带calloc)和I free它在函数返回之前(在处理完C字符串之后).
当我使用cl.exe(在Microsoft Visual C++中)编译此代码时,即使警告级别较低,该free调用也会触发警告C4090.因为free需要一个void *,这告诉我编译器不喜欢我已经转换const char **为a void *.我创建了一个简单的例子来证实这一点,我尝试将a转换const void **为void *:
/* cast.c - Can a const void** be cast …Run Code Online (Sandbox Code Playgroud) 在一个相关的问题中,它说没有指向非成员const函数的指针.另外,C++ 11 8.3.5/6说
cv-qualifier-seq在函数声明符中的作用与在函数类型之上添加cv-qualification不同.在后一种情况下,忽略cv限定符.[注意:具有cv-qualifier-seq的函数类型不是cv限定类型; 没有cv限定的函数类型. - 尾注]
如果我理解正确,这意味着没有非成员const函数.(虽然这些函数不是常量,但不能按照3.10/6进行修改).特别是,指向const函数的指针是没有意义的.
但是,似乎有些编译器会在类型推导上下文中创建指向const函数的指针.例如,考虑代码:
#include <iostream>
void f() {}
template <typename T> void g( T*) { std::cout << "non const" << std::endl; }
template <typename T> void g(const T*) { std::cout << "const " << std::endl; }
int main() {
g(f);
}
Run Code Online (Sandbox Code Playgroud)
当使用GCC和Intel编译时,代码输出"非常量",正如我从上面的引用中所期望的那样.但是,使用Clang和Visual Studio编译时输出为"const".
我的解释是否正确?
更新:
在评论之后,我试图澄清我不是在讨论const成员函数.我对非成员函数感兴趣(但同样的参数也可能适用于非静态成员函数).我也改变了问题标题,使其更精确.
与g(f)上面提到的解决方案一致,以下行对于GCC和英特尔而言是非法的,但对于Clang和Visual Studio则不行
const auto* ptr = &f;
Run Code Online (Sandbox Code Playgroud)
更新2:
我同意Andy Prowl的解释,并选择了他的答案.然而,在那之后,我意识到这个问题是CWG 公开问题.
我最近一直在学习C++,并且今天已经介绍了const和const正确性的概念.为了更好地理解这个理论,我一直在编写一系列简单的程序来确保我理解这个概念.我以为我理解了一切,但是当在其中一个程序中使用auto关键字时,我似乎有点卡住了.
为了测试我理解const指针是如何工作的,我编写了一个简单的程序.我不打算发布整件事,因为它只有两部分是相关的.我有一个类型为int的const数据成员的类:
const int tryToChangeMe;
Run Code Online (Sandbox Code Playgroud)
在这个类中,我还有一个成员函数,它返回一个指向上面的const int的const指针:
const int* const MyClass::test()
{
return &tryToChangeMe;
}
Run Code Online (Sandbox Code Playgroud)
在我的main函数中,然后调用上面的函数,使用auto关键字.为了测试我认为我对const的了解是正确的,然后尝试通过指针重新分配tryToChangeMe变量.像这样:
auto temp = myClass.test();
*temp = 100;
Run Code Online (Sandbox Code Playgroud)
正如我所料,由于我在尝试为const变量赋值时所引起的错误,程序无法编译.但是,我不只是返回一个指针常量,我回到一个常量指针常量(至少这是我认为我做了).所以为了测试这个,我试图将指针重新分配给一个新的内存地址,相信我会得到类似的编译错误:
temp = new int;
Run Code Online (Sandbox Code Playgroud)
但令人困惑的是,该程序编译没有任何问题.通过调试器逐步调试显示,指针正在丢失其原始地址并被分配一个全新的地址.想知道发生了什么,我偶然发现了删除auto关键字并将其替换为变量的完整类型:
const int* const temp = myClass.test();
Run Code Online (Sandbox Code Playgroud)
再次测试所有内容后,结果与预期一致,这次我无法将指针重新分配给新地址.
毕竟,我想我的问题是,为什么?为什么auto关键字允许你绕过指针的const限定符?我做错什么了吗?
顺便说一句,我不确定它是否重要,但我正在使用Visual Studio 2015预览版
据已知特征的C++,一个常量引用延伸从函数返回的临时对象的生命时间,但是它可以接受使用恒定的参考到临时对象的成员从函数返回?
例:
#include <string>
std::pair<std::string, int> getPair(int n)
{
return {std::to_string(n), n};
}
int main(int, char*[])
{
const int x = 123456;
const auto& str = getPair(x).first;
printf("%d = %s\n", x, str.c_str());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
123456 = 123456
Run Code Online (Sandbox Code Playgroud) const ×10
c++ ×8
c ×3
c++11 ×3
pointers ×2
auto ×1
exception ×1
keyword ×1
objective-c ×1
optimization ×1
reference ×1
rvalue ×1
visual-c++ ×1