传递给函数的临时对象是否被视为const?

时间:2020-03-27 20:01:43

标签: c++ casting constants

我已将参数设为const&函数,因为我希望能够向其传递“字符串文字”。但是我想知道是否可以修改引用,像这样:

void addObjectToDictionary(int* obj, const std::string& name)
{
     for (int = 0; i < 10; ++i)
     {
           if (/*Name already exists in dictionary*/)
                name = "object" + std::to_string(rand());
           else { /*Add obj to dictionary*/; return; }
     }
}

int main()
{
     addObjectToDictionary(new int(6), "somename");
)

我想知道是否没有定义掉std :: string引用上的const。该网站上的另一个答案是:

const_cast仅在投射最初非常量的变量时才是安全的。例如,如果您有一个采用const char *参数的函数,并且传入了可修改的char *,则将const_cast该参数返回给char *并进行修改是安全的。

但是,我想知道调用函数时创建的临时std :: string对象是否被视为const。

2 个答案:

答案 0 :(得分:3)

我已将参数设为const&函数,因为我希望能够向其传递“字符串文字”。

如果您有兴趣,可以像这样使用字符串文字的确切类型...

"string literal"

...是const char[15]。碰巧的是,std::string的构造函数采用const char*const char[15]会自动衰减为const std::string&,因此字符串文字会绑定到(const char[15]) --> decay --> (const char*) --> bind --> std::string::string( const char* ) 参数。

std::string

这将创建一个临时std::string,其中包含字符串文字的副本。然后,您的函数将那个临时const std::string&当作const原始临时文件实际上不是const 原始临时文件是否为const显然在标准中是一厢情愿的,但 {根据另一个答案,在C ++ 17中为{1}}。

但是我想知道是否可以修改参考

我想知道是否没有定义掉std :: string引用上的const。

如果要修改临时目录,则不需要const_cast。该语言为您提供了一种以非const方式绑定到临时对象的方式:rvalue引用。

// this is a const lvalue reference
// it binds to temporaries
void addObjectToDictionary(int* obj, const std::string& name);

// this is an rvalue reference
// it also binds to temporaries, and will bind to temporaries instead of a
// const lvalue reference if both overloads exist
void addObjectToDictionary(int* obj, std::string&& name);

您陈述的问题的答案...

但是,我想知道调用函数时创建的临时std :: string对象是否被视为const。

根据另一个答案,对于C ++ 17,

...是否,临时不是const 显然是。 但是,y 您也不应通过const左值引用来临时使用const并将其抛弃,因为该签名也实际上绑定到了const对象。相反,您可以使用const引用参数以非{rvalue的方式绑定到临时目录。

作为奖励,如果您想直接绑定到字符串文字,则可以执行以下操作:

// this templates functions that bind to the exact type of any string literal
template<std::size_t N>
void addObjectToDictionary(int* obj, const char ( &name )[N] );

此模板生成绑定到任意长度的字符串文字的确切类型的函数。这可能有点过分。

编辑

注释中有建议按值取字符串(std::string,无参考)。这也是将字符串“下沉”到函数中的一种完全有效的方法。

// this will bind to string literals without creating a temporary
void addObjectToDictionary(int* obj, std::string name);

那么,这里发生的情况有些不同。将字符串文字传递给const std::string&参数时,您会获得对临时const的{​​{1}}引用。将字符串文字传递给普通的旧std::string值时,曾经是临时值的现在是您自己想要的std::string值对象,该对象由字符串文字构造而成。

答案 1 :(得分:2)

首先,您可以随时使用const_cast。只是,如果您尝试修改实际上是const的对象,则编译器无法在编译时捕获该行为,则行为是不确定的。使用const_cast只会增加您这样做的风险。

关于您的情况临时变量是否为const的问题:答案似乎是“是”。关于针对每个C ++标准版本的引用初始化的措辞,已经有许多缺陷报告,因此,我将在这里讨论C ++ 17的措辞。标准中的相关规定是[dcl.init.ref] /5.2.2.1:

如果T1T2是类类型,并且T1T2没有引用相关,则使用复制初始化规则考虑用户定义的转换通过用户定义的转换(类型为“ cv1 T1”的对象)(11.6、16.3.1.4、16.3.1.5);如果相应的非引用副本初始化格式不正确,则程序格式不正确。如非引用副本初始化所述,对转换函数的调用结果将用于直接初始化引用。对于这种直接初始化,不考虑用户定义的转换。

对于std::string prvalue是否经过cv限定尚不清楚,但是在任何情况下prvalue都将用于初始化引用,该引用受p5.2.1的约束,这要求prvalue继承要初始化的引用的cv限定词。因此很明显,创建的临时对象的类型为const std::string

所以,在:

const std::string& name = "somename";

您会得到一个const临时工,但是当您这样做时

std::string&& name = "somename";

您会得到一个非const临时字符。临时人员的简历合格与参考人的简历相符。