标签: temporary-objects

在临时字符串上使用string :: c_str

关于临时对象何时被销毁,这是否有效:

FILE *f = fopen (std::string ("my_path").c_str (), "r");
Run Code Online (Sandbox Code Playgroud)

在评估调用fopen之后或之后的第一个参数后,是否会立即销毁临时值fopen.

使用以下代码进行测试:

#include <cstdio>
using namespace std;
struct A {
        ~A() { printf ("~A\n"); }
        const char *c_str () { return "c_str"; }
};
void foo (const char *s) { printf ("%s\n", s); }
int main () {
        foo (A().c_str());
        printf ("after\n");
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

得到:

c_str
~A
after
Run Code Online (Sandbox Code Playgroud)

这表示首先评估整个语句,然后销毁任何临时语句.这种排序是由标准还是特定于实现的强制要求?

c++ destructor temporary-objects

7
推荐指数
1
解决办法
1056
查看次数

const引用临时引用

#include <iostream>
using namespace std;

struct CL
{
    CL()
    {
        cout<<"CL()"<<endl;
    }
    CL(const CL&)
    {
        cout<<"CL(const CL&)"<<endl;
    }
    ~CL()
    {
        cout<<"~CL()"<<endl;
    }
};

CL cl;

CL fnc()
{
    return cl;
}

int main() {
    cout<<"start"<<endl;
    const CL& ref=static_cast<const CL&>(fnc());
    //...Is "ref" valid here??
    cout<<"end"<<endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

fnc()返回的临时对象的生命周期是多少?它是"ref"或临时引用static_cast(fnc())的生命周期,它在语句结束时被销毁了吗?

gcc的输出(fnc()的生命周期是"ref"的生命周期):

CL()  //global object "cl"
start
CL(const CL&)
end
~CL()
~CL() //global object "cl"
Run Code Online (Sandbox Code Playgroud)

VS2013的输出(fnc()的寿命是临时参考的寿命):

CL()  //global object "cl"
start
CL(const CL&)
~CL()
end
~CL() //global object "cl"
Run Code Online (Sandbox Code Playgroud)

标准是什么?

c++ reference language-lawyer temporary-objects

7
推荐指数
1
解决办法
438
查看次数

在c ++ 11中将指针传递给临时?

我有一个现有的功能:

void foo(const Key* key = nullptr)
{
  // uses the key
}
Run Code Online (Sandbox Code Playgroud)

我想将它指向临时Key对象(即rvalue),如:

foo(&Key());
Run Code Online (Sandbox Code Playgroud)

这会导致编译错误,但是在c ++ 11/14中有一种方法可以做到这一点吗?我当然可以这样做:

Key key;
foo(&key);
Run Code Online (Sandbox Code Playgroud)

但我不需要对象Key,我只需要它在foo()和foo()中

或者我可以这样做:

foo(new Key());
Run Code Online (Sandbox Code Playgroud)

但是这个对象不会被删除.

c++ temporary-objects c++11 c++14 c++17

7
推荐指数
3
解决办法
956
查看次数

什么时候临时生命周期扩展在现代C++中有用?

在C++中,您可以将函数的返回值(返回值,而不是引用)绑定到const引用,代码仍然有效,因为此临时的生命周期将延长到范围结束.例如

std::string get_string() {
    return "abc";
}


void f() {
    const std::string& str = get_string();
    std::cout << str; // valid, str is not dangling reference.
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,什么时候有用,例如何时是代码

A get_a();
const A& a = get_a();
Run Code Online (Sandbox Code Playgroud)

比代码更好

A get_a();
A a = get_a();
Run Code Online (Sandbox Code Playgroud)

以什么方式(例如更快,更小的二进制大小等)?应该是什么A,get_a以及调用后的代码get_a

我已经手工测试了几个案例,并且在每种情况下它似乎具有相同数量的副本和移动.

让我们将这个问题限制为当前的C++标准,现代版本的编译器和构建并启用了优化(O2,O3或其他编译器的等价物)

c++ lifetime temporary-objects

7
推荐指数
1
解决办法
356
查看次数

基于范围的for循环在临时范围上

感谢valgrind中的一些分段错误和警告,我发现这段代码不正确,并且在for-range循环中有一些悬空引用.

#include<numeric>
#include<vector>

auto f(){
    std::vector<std::vector<double>> v(10, std::vector<double>(3));
    iota(v[5].begin(), v[5].end(), 0);
    return v;
}

int main(){
    for(auto e : f()[5])
        std::cout << e << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它看起来好像beginend从临时取出,并循环丢失.

当然,一种方法是做

    auto r = f()[5];
    for(auto e : r)
        std::cout << e << std::endl;
Run Code Online (Sandbox Code Playgroud)

但是,我想知道为什么for(auto e : f()[5])是一个错误,如果有更好的方法或某种方式设计f或甚至容器(std::vector)以避免这个陷阱.

随着迭代循环是比较明显的,为什么这个问题发生(beginend来自不同的临时对象)

for(auto it = f()[5].begin(); it != f()[5].end(); ++it)
Run Code Online (Sandbox Code Playgroud)

但是在for-range循环中,就像在第一个例子中一样,这个错误似乎很容易.

c++ temporary-objects c++11 c++20 for-range

7
推荐指数
2
解决办法
682
查看次数

绑定到引用时临时对象生命周期扩展异常的基本原理是什么?

在C++ 11标准的12.2中:

绑定引用的临时对象或绑定引用的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了:

  1. 绑定到构造函数的ctor-initializer(12.6.2)中的引用成员的临时绑定将持续存在,直到构造函数退出.

  2. 函数调用(5.2.2)中的引用参数的临时绑定将持续到包含该调用的完整表达式完成为止.

  3. 函数返回语句(6.6.3)中返回值临时绑定的生命周期未扩展; 临时在return语句中的full-expression结束时被销毁.

  4. 在new-initializer(5.3.4)中对引用的临时绑定将持续到包含new-initializer的full-expression完成为止.

并且标准中有最后一个案例:

struct S {
  int mi; 
  const std::pair<int,int>& mp;
}; 
S a { 1,{2,3} };  // No problem.
S* p = new S{ 1, {2,3} };  // Creates dangling reference
Run Code Online (Sandbox Code Playgroud)

对我而言,2. and 3.理解并容易达成一致.但是原因是1. and 4.什么?这个例子对我来说看起来很邪恶.

c++ object-lifetime temporary-objects c++11

6
推荐指数
1
解决办法
375
查看次数

是否在?:expression中创建的C++临时对象的生命周期是通过将其绑定到本地const引用来扩展的?

我不清楚临时对象的生命周期是通过将它绑定到?:表达式中的const引用来扩展的:

class Foo {...};

Foo *someLValue = ...;

const Foo& = someLValue ? *someLValue : Foo();
Run Code Online (Sandbox Code Playgroud)

通过将默认构造函数Foo()通过绑定到本地const ref来扩展创建临时文件的生命周期,即使绑定是有条件的吗?或者这会创建一个悬空引用,因为Foo()的临时值将在?:表达式的末尾被销毁?

c++ reference const-reference temporary-objects

6
推荐指数
1
解决办法
231
查看次数

是否可以检测对象是否是成员函数内的临时对象?

我正在使用指向实现的成语实现不可变对象上的装饰器模式.基本上我的设置看起来像这样

struct Object : ObjectBase {
     void doSmth() override {
         impl->doSmth();
     }
     // this is the function I'd like to implement
     Object decorateWith(std::unique_ptr<ObjectDecorator>&&);
private:
     std::unique_ptr<ObjectBase> impl;
};

struct ObjectDecorator : ObjectBase {
    void doSmth() override {
        // do some stuff
        impl->doSmth();
        // do some more stuff
    }
private:
    std::unique_ptr<ObjectBase> impl;
};
Run Code Online (Sandbox Code Playgroud)

这里,decorateWith函数应该具有不同的行为,这取决于它是否是callen on的对象是否是临时的.如果在非临时对象上调用它,它应该返回一个新的Object实例,我必须在其中创建当前Object的深层副本并将其存储在装饰器的unique_ptr中,同时新的Object本身的impl指针指着装饰者.但是,如果在临时调用decorateWith,则只需创建一个ObjectDecorator,只需将当前对象的impl指针移动到装饰器的impl指针中,然后让对象指向新的装饰器即可.

为了阻止我需要一种方法来确定从decorateWith中调用对象是否是临时的,然后根据该检查的结果使用tag-dispatch.那可能吗?

最好的Xodion

编辑:示例调用者代码可能如下所示:

  • decorateWith是在非临时的上调用的

    int main() {
        Object x{};
    
        // this call does not modify x so it can be reused later
        Object y = x.decorateWith{std::make_unique<ObjectDecorator>()};
        y.doSmth(); …
    Run Code Online (Sandbox Code Playgroud)

c++ rvalue temporary-objects

6
推荐指数
1
解决办法
513
查看次数

为什么用指向非 const 的指针初始化的对 const 指针的右值引用不会创建临时对象并将其与其绑定?

如果我们想用不同的类型初始化引用,我们需要将其设置为 const (const type*),以便可以隐式生成临时对象并将引用绑定到 with。或者,我们可以使用右值引用并实现相同的[1]:

右值引用可用于延长临时对象的生命周期(注意,对 const 的左值引用也可以延长临时对象的生命周期,但不能通过它们进行修改):

[...]

样品

情况1

double x = 10;

int &ref = x; //compiler error (expected)
Run Code Online (Sandbox Code Playgroud)

案例2

double x = 10;
const int &ref = x; //ok
Run Code Online (Sandbox Code Playgroud)

案例3

double x = 10;
int &&ref = x; //ok
Run Code Online (Sandbox Code Playgroud)

如果我们尝试对 const 指针(const type* &)做同样的事情,并用非 const 指针(type*)初始化它,与我预期的不同,只有情况 2 有效。为什么情况3会导致编译器错误?为什么没有生成临时文件?

情况1

int x = 10;

int *pX = &x;

const int* &ref = pX; //compiler error (expected)
Run Code Online (Sandbox Code Playgroud)

案例2

int x = 10;
int *pX = &x;
const int* …
Run Code Online (Sandbox Code Playgroud)

c++ pointers reference rvalue-reference temporary-objects

6
推荐指数
1
解决办法
533
查看次数

可以将 const T*&amp;&amp; 绑定到 T* 类型的 xvalue 吗?

考虑以下代码:(https://godbolt.org/z/8W699x6q6

int* p;
const int*&& r = static_cast<int*&&>(p);
Run Code Online (Sandbox Code Playgroud)

注意:const int*&&是指向 的指针的右值引用const int

Clang 编译它,并r绑定到一个临时对象:

p: .quad   0
r: .quad   _ZGR1r_ // r is a reference to a temporary object, otherwise this would be p
Run Code Online (Sandbox Code Playgroud)

GCC 拒绝此代码:

<source>:2:18: error: binding reference of type 'const int*&&' to 'int*' discards qualifiers
    2 | const int *&&r = static_cast<int*&&>(p);
      |                  ^~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我认为 GCC 正确地实现了CWG 2352[dcl.init.ref] p4的更改,但我不确定我的解释是否正确。这里哪个编译器是正确的?


注意:本问题中的示例受到CWG 2018中提到的最后一行代码的启发。

注意:如果允许绑定const int*&& …

c++ const-correctness language-lawyer temporary-objects reference-binding

6
推荐指数
1
解决办法
269
查看次数