C++ 是否可以通过常量引用获取参数,同时禁止转换以使临时变量不';你没有通过吗?
有时,我们喜欢通过引用获取一个大参数,如果可能的话,还可以使引用常量表明它是一个输入参数。但是通过使引用常量,编译器允许自己转换错误类型的数据。这意味着它没有那么有效,但更令人担忧的是,我认为我指的是原始数据;也许我会接受它的地址,但没有意识到我实际上是在接受一个临时雇员的地址 在此代码中调用C++ 是否可以通过常量引用获取参数,同时禁止转换以使临时变量不';你没有通过吗?,c++,constants,C++,Constants,有时,我们喜欢通过引用获取一个大参数,如果可能的话,还可以使引用常量表明它是一个输入参数。但是通过使引用常量,编译器允许自己转换错误类型的数据。这意味着它没有那么有效,但更令人担忧的是,我认为我指的是原始数据;也许我会接受它的地址,但没有意识到我实际上是在接受一个临时雇员的地址 在此代码中调用bar失败。这是可取的,因为引用的类型不正确。对bar_const的调用也是错误的类型,但它会以静默方式编译。这对我来说是不可取的 #include<vector> using namespac
bar
失败。这是可取的,因为引用的类型不正确。对bar_const
的调用也是错误的类型,但它会以静默方式编译。这对我来说是不可取的
#include<vector>
using namespace std;
int vi;
void foo(int &) { }
void bar(long &) { }
void bar_const(const long &) { }
int main() {
foo(vi);
// bar(vi); // compiler error, as expected/desired
bar_const(vi);
}
该示例基于局部变量,但我希望它也能与参数一起使用。如果我意外地将ref传递给临时对象或ref-to-a-copy,而我认为我将传递一些轻量级的东西,例如ref传递给左值,那么我希望得到某种错误消息。这只是一个“编码标准”的东西——如果我真的想允许将ref传递给临时变量,那么我将使用一个简单的
const X&
。(我发现这很有用。)你做不到,即使你可以,也可能没有多大帮助。
考虑:
void another(long const& l)
{
bar_const(l);
}
即使您可以以某种方式阻止将绑定到临时对象作为
bar_const
,类似于另一个
的函数可以通过引用调用
一定会有一个临时的,你也会有同样的结果
如果您不能接受临时,则需要使用对
非常量或指针:
void bar_const(long const* l);
需要一个左值来初始化它。当然,像这样的函数
void another(long const& l)
{
bar_const(&l);
}
仍然会引起问题。但如果你在全球范围内采用该公约
如果对象生存期必须超过调用结束时,请使用指针,
然后,希望《另一部的作者会思考他为什么要
地址,并避免它。如果“大参数”是一个类,那么要做的第一件事是确保将任何单参数构造函数标记为显式(除了复制构造函数):
这适用于具有默认参数的构造函数,这些参数可能也可以用单个参数调用
然后它将不会自动转换为,因为编译器没有隐式构造函数来执行转换。您可能没有任何生成该类型的全局转换运算符,但如果有,则
如果这对您不起作用,您可以使用一些模板魔术,如:
template <typename T>
void func(const T &); // causes an undefined reference at link time.
template <>
void func(const BigType &v)
{
// use v.
}
模板
无效函数(常数T&);//在链接时导致未定义的引用。
模板
无效函数(常量BigType&v)
{
//使用v。
}
>P>我认为你的例子是 int 和长< /Cord>是一个红色的鲱鱼,就像在规范C++中,你永远不会通过const引用传递建设者类型:你通过值或非const引用传递它们。
因此,让我们假设您有一个大型的用户定义类。在本例中,如果它为您创建临时对象,则意味着您为该类创建了隐式转换。您所要做的就是将所有转换构造函数(可以使用单个参数调用的构造函数)标记为explicit
,编译器将阻止自动创建这些临时构造函数。例如:
class Foo
{
explicit Foo(int bar) { }
};
这很容易解决:停止引用值。如果要确保参数可寻址,请将其设置为地址:
这样,用户必须传递一个指针。而且你不能得到一个指向临时文件的指针(除非用户非常恶意)
话虽如此,我认为你对这件事的想法是。。。头脑不清醒。归结到这一点
也许我会接受它的地址,但没有意识到我实际上是在接受一个临时雇员的地址
获取一个恰好是临时的常量&
的地址实际上是可以的。问题是你不能长期保存它。你也不能转让它的所有权。毕竟,您得到了一个const
引用
这就是问题的一部分。如果您使用常量&
,您的界面会显示“我可以使用此对象,但我不拥有它,也不能将所有权授予其他人。”因为您不拥有该对象,所以无法长期存储它。这就是const&
的意思
取而代之的是常量*
,可能会有问题。为什么?因为你不知道那个指针是从哪里来的。谁拥有这个指针const&
有许多语法保护措施来防止你做坏事(只要你不使用它的地址)<代码>常量*
没有任何内容;你可以把这个指针复制到你的心上。您的界面没有说明是否允许您拥有该对象或将所有权转让给其他人
这就是为什么C++11具有智能指针,如unique\u ptr
和shared\u ptr
。这些指针可以描述真实的内存所有权关系
如果您的函数按值获取一个唯一的\u ptr
,则您现在拥有该对象。如果它需要一个共享\u ptr
,那么您现在共享该对象的所有权。有一些语法保证可以确保所有权(同样,除非您采取了令人不快的步骤)
如果您不使用C++11,您应该使用Boost智能指针来实现类似效果。如果您可以使用C++11(或其部分),这很容易:
void f(BigObject const& bo){
// ...
}
void f(BigObject&&) = delete; // or just undefined
这将起作用,因为对于临时对象,绑定到右值引用比绑定到常量引用更可取
您还可以利用隐式转换序列中只允许单个用户定义的转换这一事实:
struct BigObjWrapper{
BigObjWrapper(BigObject const& o)
: object(o) {}
BigObject const& object;
};
void f(BigObjWrapper wrap){
BigObject const& bo = wrap.object;
// ...
}
.(回答我自己的问题,感谢您回答我提出的另一个问题。谢谢@hvd。)
void bar_const(const long *) { }
void f(BigObject const& bo){
// ...
}
void f(BigObject&&) = delete; // or just undefined
struct BigObjWrapper{
BigObjWrapper(BigObject const& o)
: object(o) {}
BigObject const& object;
};
void f(BigObjWrapper wrap){
BigObject const& bo = wrap.object;
// ...
}
void foo( const volatile Input & input, Output & output) {
}
foo(input, output); // compiles. good
foo(get_input_as_value(), output); // compile failure, as desired.
void foo( const_lvalue<Input> input, Output & output) {
}
template<typename T>
struct const_lvalue {
const T * t;
const_lvalue(const volatile T & t_) : t(const_cast<const T*>(&t_)) {}
const T* operator-> () const { return t; }
};