带和不带指针声明符的 C++11 自动声明
C++11 auto declaration with and without pointer declarator
bar1
和bar2
的类型有什么区别?
int foo = 10;
auto bar1 = &foo;
auto *bar2 = &foo;
如果bar1
和bar2
都是int*
,在bar2
声明中写指针声明符(*
)有意义吗?
声明完全相同。 auto
与 template type deduction 的工作方式(几乎)相同。明确地放置星号使代码更容易阅读,并让程序员意识到 bar2
是一个指针。
就 C++ 代码的解释而言,这无关紧要;你可以写任何你想写的。但是,存在样式和可读性问题:通常,您不应在类型别名中隐藏指针、引用和 CV 限定符,甚至智能指针,因为这会使 reader 更难理解那是这是怎么回事。类型别名应该封装语义相关的类型内容,而限定符和修饰符应该保持可见。所以更喜欢以下内容:
using Foo = long_namespace::Foobrigation<other_namespace::Thing>;
using MyFn = const X * (int, int);
std::unique_ptr<Foo> MakeThatThing(MyFn & fn, int x) // or "MyFn * fn"
{
const auto * p = fn(x, -x);
return p ? p->Create() : nullptr;
}
不要说:
using PFoo = std::unique_ptr<Foo>; // just spell it out
using MyFn = int(&)(int, int); // unnecessary; & is easy to spell
auto p = fn(x, -x); // Don't know that p is a pointer
另请注意,引用限定符(与指针不同)真正改变了正在声明的变量的类型,因此它们不是可选的:
X & f();
auto a = f(); // copy!
auto & b = f(); // b is the same as the return value of f()
最后,添加明确的 const 指针限定可以提供帮助 const-correctness。考虑下一个示例,其中一个容器包含 pointers-to-mutable,但我们只需要 const 访问。只是 auto *
会推导出一个指向可变的指针,我们可以通过明确地说 const
来避免这种情况:
std::vector<X*> v = /* ... */;
for (const auto * p : v)
{
observe(p->foo()); // no need for a mutable *p
}
在此具体示例中,bar1
和 bar2
是相同的。这是个人喜好的问题,尽管我会说 bar2
更容易阅读。
但是,这不适用于在 example 中看到的引用:
#include <iostream>
using namespace std;
int main() {
int k = 10;
int& foo = k;
auto bar = foo; //value of foo is copied and loses reference qualifier!
bar = 5; //foo / k won't be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k << endl;
auto& ref = foo;
ref = 5; // foo / k will be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k;
return 0;
}
使用 auto *
"documents intention"。而auto *p = expr;
只有expr
returns指针才能正确推导。示例:
int f();
auto q = f(); // OK
auto *p = f(); // error: unable to deduce 'auto*' from 'f()'
正如其他人所说,他们将生成相同的代码。星号是线路噪音(并且使得从原始指针切换到智能指针变得更加困难,例如,如果 &foo
被 get_foo()
替换)。如果你想明确,那么一定要明确;但是当你使用类型推断时,让编译器完成它的工作。缺少星号并不意味着对象不是指针。
当您使用 const
限定符时会有很大的不同:
int i;
// Const pointer to non-const int
const auto ip1 = &i; // int *const
++ip1; // error
*ip1 = 1; // OK
// Non-const pointer to const int
const auto* ip2 = &i; // int const*
++ip2; // OK
*ip2 = 1; // error
bar1
和bar2
的类型有什么区别?
int foo = 10;
auto bar1 = &foo;
auto *bar2 = &foo;
如果bar1
和bar2
都是int*
,在bar2
声明中写指针声明符(*
)有意义吗?
声明完全相同。 auto
与 template type deduction 的工作方式(几乎)相同。明确地放置星号使代码更容易阅读,并让程序员意识到 bar2
是一个指针。
就 C++ 代码的解释而言,这无关紧要;你可以写任何你想写的。但是,存在样式和可读性问题:通常,您不应在类型别名中隐藏指针、引用和 CV 限定符,甚至智能指针,因为这会使 reader 更难理解那是这是怎么回事。类型别名应该封装语义相关的类型内容,而限定符和修饰符应该保持可见。所以更喜欢以下内容:
using Foo = long_namespace::Foobrigation<other_namespace::Thing>;
using MyFn = const X * (int, int);
std::unique_ptr<Foo> MakeThatThing(MyFn & fn, int x) // or "MyFn * fn"
{
const auto * p = fn(x, -x);
return p ? p->Create() : nullptr;
}
不要说:
using PFoo = std::unique_ptr<Foo>; // just spell it out
using MyFn = int(&)(int, int); // unnecessary; & is easy to spell
auto p = fn(x, -x); // Don't know that p is a pointer
另请注意,引用限定符(与指针不同)真正改变了正在声明的变量的类型,因此它们不是可选的:
X & f();
auto a = f(); // copy!
auto & b = f(); // b is the same as the return value of f()
最后,添加明确的 const 指针限定可以提供帮助 const-correctness。考虑下一个示例,其中一个容器包含 pointers-to-mutable,但我们只需要 const 访问。只是 auto *
会推导出一个指向可变的指针,我们可以通过明确地说 const
来避免这种情况:
std::vector<X*> v = /* ... */;
for (const auto * p : v)
{
observe(p->foo()); // no need for a mutable *p
}
在此具体示例中,bar1
和 bar2
是相同的。这是个人喜好的问题,尽管我会说 bar2
更容易阅读。
但是,这不适用于在 example 中看到的引用:
#include <iostream>
using namespace std;
int main() {
int k = 10;
int& foo = k;
auto bar = foo; //value of foo is copied and loses reference qualifier!
bar = 5; //foo / k won't be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k << endl;
auto& ref = foo;
ref = 5; // foo / k will be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k;
return 0;
}
使用 auto *
"documents intention"。而auto *p = expr;
只有expr
returns指针才能正确推导。示例:
int f();
auto q = f(); // OK
auto *p = f(); // error: unable to deduce 'auto*' from 'f()'
正如其他人所说,他们将生成相同的代码。星号是线路噪音(并且使得从原始指针切换到智能指针变得更加困难,例如,如果 &foo
被 get_foo()
替换)。如果你想明确,那么一定要明确;但是当你使用类型推断时,让编译器完成它的工作。缺少星号并不意味着对象不是指针。
当您使用 const
限定符时会有很大的不同:
int i;
// Const pointer to non-const int
const auto ip1 = &i; // int *const
++ip1; // error
*ip1 = 1; // OK
// Non-const pointer to const int
const auto* ip2 = &i; // int const*
++ip2; // OK
*ip2 = 1; // error