我一直读到,在函数调用的情况下,临时变量只能与非常量引用参数绑定。
情况1:-
例如:-
class Simple{
public:
int i;
Simple(Simple &f)
{
i = f.i + 1;
}
Simple(int j)
{
i = j;
}
};
int main()
{
Simple f1 = Simple(2); // error no matching call fruit::fruit(fruit)...
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这会给我错误,因为我试图用非常量引用参数临时绑定。
案例2:-
try
{
throw e;
}
catch ( exception& e )
{
}
Run Code Online (Sandbox Code Playgroud)
我已经了解到,当我们抛出异常时,真正传递给 catch 的是抛出的原始异常的副本,即为抛出的对象创建一个临时对象,然后将其传递给 catch 子句。
catch 正在做的是通过非常量引用来捕获这个异常。这与我在案例 1 中展示的相反。
所以,我的问题是:-
1) 是否有允许临时绑定到非常量引用的特定场景。
2)如果有那么在允许这些例外时考虑了哪些因素。
我在一些代码库上尝试了 Coverity,我在一个类似于
struct Foo
{
std::string name;
};
Foo getFoo();
//...
const auto& name = getFoo().name;
useName(name);
Run Code Online (Sandbox Code Playgroud)
这个代码有效吗?
我的直觉是它确实是无效的。但是,在搜索证明时,我遇到了[class.temporary]/6.4,这似乎表明它实际上格式良好。然而,Coverity 发出警告,Coverity 肯定是由一些比我更能解释标准的聪明人写的。
发出的具体 Coverity 警告是
取消引用返回的或超出范围的堆栈指针将在其作用域之后或函数返回之后访问堆栈上的无效位置。
在whateverSurroundingFunction() 中:指向在范围外返回或使用的局部堆栈变量的指针(CWE-562)
在随后的使用中name。前面的警告是
out_of_scope:类型的临时变量
Foo超出范围
和一种MRE的是这个(荣誉给@ user4581301在评论)。
SO 有一堆关于临时绑定引用的问题,但我所看到的每个问题都有略微不同的上下文,因此这里又出现了另一个问题。
我试图更好地理解如何将左值和右值作为引用处理,因此我创建了这个玩具示例:
\n#include <iostream>\n\nstruct Val\n{\n Val(int num) : num(num){};\n ~Val()\n {\n std::cout << "Destructing with value " << num << std::endl;\n }\n\n int num;\n};\n\nconst Val &test(const Val &val)\n{\n return val;\n}\nint main()\n{\n std::cout<< "Creating foo with value 5" <<std::endl;\n const Val &foo = test(Val(5));\n std::cout<< "Creating bar with value 3" <<std::endl;\n const Val &bar(3);\n std::cout<< "Finishing main function" <<std::endl;\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n这打印出:
\nCreating foo with value 5\nDestructing with value 5\nCreating bar with value 3\nFinishing main function\nDestructing with value 3\n …Run Code Online (Sandbox Code Playgroud) struct test{
char c_arr[1];
};
test array[1] = {{1}};
test get(int index){
return array[index];
}
int main(){
char* a = get(0).c_arr;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译它g++没有警告但clang++打印以下内容:
warning: temporary whose address is used as value of local variable 'a' will be destroyed at the end of the full-expression
Run Code Online (Sandbox Code Playgroud)
这不正确吗?不get(0).c_arr返回指向全局数组的指针?
还是get(0)返回一个临时变量并且编译器错误地认为c_arr它只是它的一个实例,而不是全局变量?
为什么将此临时变量传递给函数可以在没有警告的情况下工作?
void call(char* in){}
int main(){
call(get(0).c_arr);
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在这里,当我推入堆栈时,为什么对象会被销毁?
#include <iostream>
#include <stack>
class One
{
private:
int i;
public:
One(int i) {this->i = i;}
~One() {std::cout << "value " << this->i << " is destroyed\n";}
};
int main()
{
std::stack<One> stack;
stack.push(One(1));
stack.push(One(2));
std::cout << "Now I'll stop\n";
}
Run Code Online (Sandbox Code Playgroud)
我之前预计不会看到任何输出Now I'll stop。但我明白了
value 1 is destroyed
value 2 is destroyed
Now I'll stop
value 1 is destroyed
value 2 is destroyed
Run Code Online (Sandbox Code Playgroud)
如果我想防止它们被破坏,我该怎么办?
我知道临时对象的生命周期在创建它的完整表达式处或之前结束,除非它绑定到引用,在这种情况下,它的生命周期将扩展到引用的生命周期,这给了我们一个下限临时对象的存储持续时间结束。
考虑以下代码(最小版本):
#include <iostream>
struct Base
{
virtual ~Base() {}
virtual void test() const { std::cout << "base"; }
};
struct Derived : public Base
{
void test() const { std::cout << "derived"; }
};
struct Composite
{
const Derived &ref;
Composite(const Derived &ref) : ref(ref) {}
void testRef() const { ref.test(); }
};
int main()
{
Composite c((Derived()));
c.testRef();
}
Run Code Online (Sandbox Code Playgroud)
当使用最新的MinGW g ++时,这实际上产生了"基础"!这是编译器错误还是我错过了什么?有人可以在VS中测试这个吗?
我认为自己是一位经验丰富的C++程序员,经常使用多态,基于堆栈的引用,临时对象(C++标准12.2)等.因此我知道应该应用终身延长.
只有在Base(虚拟或非虚拟)中定义析构函数并使用临时(即后续用法生成'derived')时,才会出现此行为:
int main()
{
Derived d;
Composite c(d);
c.testRef();
}
Run Code Online (Sandbox Code Playgroud) MemRef是一个小对象,包含指向内存的指针和长度.它是优化项目的核心,可以最大限度地减少关键部分中的字符串复制.令牌是一个deque<MemRef>.
当我在输入缓冲区中识别标记时,我想构造MemRefs并将它们添加到令牌deque中.首先尝试的是:
MemRef foo(token_begin, token_len);
tokens.push_back( foo );
Run Code Online (Sandbox Code Playgroud)
自从我在这里看到dtor调用以来,它让我觉得foo正在创建,复制,然后被破坏.接下来的尝试是:
tokens.push_back( MemRef(token_begin, token_len) );
Run Code Online (Sandbox Code Playgroud)
但我看到了同样的行为.我的猜测是,正在创建一个临时文件,复制到双端队列中,然后销毁,这也许就是"移动语义"主题的来源(我很不清楚).
实际上,有没有办法MemRef直接构建令牌双端队列,而不创建和销毁临时?
(我正在使用Apple LLVM版本5.0(clang-500.2.79)和--std = c ++ 11)
我有一个class A处理我的资源(非常大).现在我需要一个这样的矢量std::vector<A> vec_of_A (3, A(int N)).问题是vector首先构造临时对象A(int N),然后从中复制构造三次然后销毁该临时对象.由于我A(int N)分配了相当大的内存,我最终(暂时)内存需求比实际需要大33%.
如何在避免不必要的构造函数vector的A同时构建?(我class A满足所有五条规则).
编辑:对不起,我没有意识到默认构造对象的重要性A.我的问题不是默认构造函数,而是参数化构造函数.
我试图理解完美转发和构造函数的相互作用.我的例子如下:
#include <utility>
#include <iostream>
template<typename A, typename B>
using disable_if_same_or_derived =
std::enable_if_t<
!std::is_base_of<
A,
std::remove_reference_t<B>
>::value
>;
template<class T>
class wrapper {
public:
// perfect forwarding ctor in order not to copy or move if unnecessary
template<
class T0,
class = disable_if_same_or_derived<wrapper,T0> // do not use this instead of the copy ctor
> explicit
wrapper(T0&& x)
: x(std::forward<T0>(x))
{}
private:
T x;
};
class trace {
public:
trace() {}
trace(const trace&) { std::cout << "copy ctor\n"; }
trace& operator=(const …Run Code Online (Sandbox Code Playgroud)