假设我有一个返回重要结果和几个不重要结果的函数.我声明它以便通过引用返回不重要的结果:
int CalculateStuff(int param1, int param2, int& result1, int& result2);
Run Code Online (Sandbox Code Playgroud)
我想调用这个函数来计算一些东西,但在调用网站我想忽略不重要的结果.我可以这样做:
...
int dummy1, dummy2;
int result = CalculateStuff(100, 42, dummy1, dummy2);
... // do something with the result
Run Code Online (Sandbox Code Playgroud)
我想在不声明虚拟变量的情况下考虑另一种方法:
int result = CalculateStuff(100, 42, *new int, *new int);
Run Code Online (Sandbox Code Playgroud)
这有内存泄漏(不可接受),但有一个优点是比"虚拟"名称更清楚地显示我的意图(忽略结果).
那么,如果我按如下方式编写会发生什么:
int result = CalculateStuff(100, 42, auto_ptr(new int).get(), auto_ptr(new int).get());
Run Code Online (Sandbox Code Playgroud)
这合法吗?执行函数代码时,临时整数是否仍然存在?我应该用unique_ptr而不是auto_ptr吗?
(请不要建议重构我的代码;我可能会 - 但首先我想了解这些东西是如何工作的)
下面的代码标准正确吗?(天马行空)
即 by-ref 捕获表示临时的转发引用,并在同一表达式中从函数返回结果 lambda 值。
当然,存储 lambda 以供以后使用会使它包含一个悬空引用,但我指的是main.
我的疑虑与这个 SO answer和潜在的这种语言缺陷有关。具体来说,有一个令人生畏的评论说“标准引用中的引用捕获生命周期规则捕获了变量,而不是数据及其范围” ——这似乎是说捕获的临时引用在我的代码中可能是无效的。
#include <stdlib.h>
#include <string.h>
#include <cassert>
template<typename F>
auto invoke(F&& f)
{
return f();
}
template<typename F>
auto wrap(F&& f)
{
return [&f]() {return f();}; // <- this by-ref capture here
}
int main()
{
int t = invoke(wrap(
[]() {return 17;}
));
assert(t == 17);
return t;
}
Run Code Online (Sandbox Code Playgroud) CWG 1815询问(稍作修改):
Run Code Online (Sandbox Code Playgroud)struct A {}; struct B { A&& a = A{}; }; B b1; // #1 B b2{A{}}; // #2 B b3{}; // #3[...]
#2是聚合初始化,它绑定B::a到初始化器中的临时对象 forb2,从而将其生命周期延长到b2.#3是聚合初始化,但不清楚非静态数据成员初始值设定项中的临时生命周期是否B::a应该像 一样延长生命周期#2,例如#1。
根据关于该问题的说明,在 Issaquah (2014-02) CWG 打算使#3行为像#2;也就是说,格式良好,并执行b3.a绑定的临时对象的生命周期扩展。但在接下来的ISO会议(拉珀斯韦尔,2014-06),分辨率为CWG 1696获得通过,表面上是解决CWG 1815,但采用的语言,似乎使#3病态的:
11 - 绑定到来自默认成员初始值设定项的引用成员的临时表达式格式错误。
但是,紧接在该条款下的示例不考虑聚合初始化(如 CWG 1815),而仅考虑构造函数的初始化;具体来说,默认构造函数定义为 defaulted:
Run Code Online (Sandbox Code Playgroud)struct A { A() = default; …
如果我们想用不同的类型初始化引用,我们需要将其设置为 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) 考虑以下代码:(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
这基本上是关于临时生命的问题.如果函数返回一个对象,但该引用未分配给变量并且仅用于调用返回对象上的方法,则临时引用是否会自动清除?
举一个具体的例子,假设有一系列方法调用:
o.method_a().method_b()
Run Code Online (Sandbox Code Playgroud)
o.method_a()当调用method_b()完成时,自动清除返回的临时引用,就好像该行写成:
tmp = o.method_a()
try:
tmp.method_b()
finally:
tmp = None
Run Code Online (Sandbox Code Playgroud)
编辑:我对一般答案感兴趣.一旦引用计数降至0,CPython就会终止对象.其他Python实现可能不会立即终止对象.我想知道Python语言是否像C++一样,它保证临时对象在创建它们的语句的末尾被销毁.(除了在Python中,问题是临时引用是否在创建它们的语句的末尾被清除.)
在C++中,类似的代码可能用以下方法实现:
class B {
public:
void method_b();
};
class A {
public:
std::shared_ptr<B> method_a();
};
A o;
o.method_a()->method_b();
Run Code Online (Sandbox Code Playgroud)
C++标准规定"临时对象被破坏作为评估全表达式的最后一步......(词法上)包含创建它们的点.即使该评估以抛出异常结束,也是如此." 在此示例中,这意味着在完全表达式的求值结束时,将立即销毁std::shared_ptr<B>由调用创建的临时对象.销毁a 意味着清除对共享对象的引用.A::method_a()o.method_a()->method_b();std::shared_ptr
通过一个例子更好地解释:
tok.h
#include <string>
static const char* defaultDelim = ".,;";
class Tokenizer {
public:
Tokenizer():
// 'delim' is the const ref member that is initialized by the temp string
delim( (altDelim.size())? altDelim : std::string(defaultDelim) )
{}
size_t scan(const std::string& str)
{ return str.find_first_of(delim); }
static void setDelim(const std::string& d) { altDelim = d; }
private:
static std::string altDelim;
const std::string& delim;
};
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include <iostream>
using namespace std;
#include "tok.h"
std::string Tokenizer::altDelim;
int main()
{
Tokenizer tok;
size_t pos = …Run Code Online (Sandbox Code Playgroud) 我想改变这个工作代码:
ofstream outfile("my_file.txt");
copy(v.begin(), v.end(), ostream_iterator<int>(outfile));
Run Code Online (Sandbox Code Playgroud)
进入这个:
copy(v.begin(), v.end(), ostream_iterator<int>(ofstream("my_file.txt")));
Run Code Online (Sandbox Code Playgroud)
换句话说,我使用ofstream对象的"匿名"或未命名版本.
两个问题:
(1)为什么第二次尝试失败?
(2)第二次尝试在风格上是否很好,或者在C++中保持所有明确命名的更好?我来自Python背景,其中对象是一直在创建的.
谢谢!!
我正在使用STL向量,它是参数的向量.
std::vector<Parameter> foo;
Run Code Online (Sandbox Code Playgroud)
我试图找到一种方法将Parameter对象添加到向量而不执行此操作:
Parameter a;
foo.push_back(a);
Run Code Online (Sandbox Code Playgroud)
我遇到了一个执行此操作的实现:
foo.push_back(Parameter()); //Using the Parameter constructor
Run Code Online (Sandbox Code Playgroud)
我认为当我创建一个对象时,构造函数被调用,反之亦然.为什么我可以将构造函数传递给函数?
当我传递文本时,以下代码中的LVALUE和RVALUE在实践上有什么区别?我的意思是,在这种特定的字符串情况下(其中字符串是字符串文字),使用RVALUE(&&)有什么好处吗?
void write_Lvalue(const std::string &text) {
//...
}
void write_Rvalue(const std::string &&text) {
//...
}
int main() {
write_Lvalue("writing the Lvalue");
write_Rvalue("writing the Rvalue");
}
Run Code Online (Sandbox Code Playgroud)