Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否可以通过常量引用获取参数,同时禁止转换以使临时变量不';你没有通过吗?_C++_Constants - Fatal编程技术网

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; }
};