请考虑以下代码:
#include <iostream>
using namespace std;
class A
{
public:
int a;
A(): a(5)
{
cout << "Constructor\n";
}
A(const A &b)
{
a = b.a;
cout << "Copy Constructor\n";
}
A fun(A a)
{
return a;
}
};
int main()
{
A a, c;
A b = a.fun(c);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面代码的输出g++ file.cpp是:
Constructor
Constructor
Copy Constructor
Copy Constructor
Run Code Online (Sandbox Code Playgroud)
上面代码的输出g++ -fno-elide-constructors file.cpp是:
Constructor
Constructor
Copy Constructor
Copy Constructor
Copy Constructor
Run Code Online (Sandbox Code Playgroud)
我知道返回值优化.我的问题是哪个复制构造函数的调用被删除(返回期间的临时对象或被复制到b的返回对象)?
如果省略的复制构造函数是用于创建b的构造函数,那么如何创建b(因为在这种情况下也没有构造函数调用)?
如果我替换行A b …
c++ copy-constructor temporary-objects return-value-optimization copy-elision
我无法想象这已经不是重复了,但我不能轻易找到答案,因为特别针对C++的更复杂的场景似乎主宰了讨论0.
在C99中取一个函数调用的参数列表中的临时构造地址是否合法?
例如,类似于init_list或init_desig_init如下的内容:
typedef struct {
int x;
int y;
} point_t;
int manhattan(point_t *p) {
return p->x + p->y;
}
int init_list() {
return manhattan(&(point_t){1, 2});
}
int init_desig_init() {
return manhattan(&(point_t){.x = 1});
}
Run Code Online (Sandbox Code Playgroud)
三大1 似乎编译好了,但我实际上找不到一个参考,解释临时的生命周期至少会通过函数调用来扩展.
0事实证明,根据下面MM的回答,我的部分搜索问题是因为我正在寻找有关临时数据的信息,而这个特定初始化结构的正确C术语是复合文字.
1我应该称之为"大跨平台三",尊重MSVC,但实际上我的意思是"C编译器神棒支持".
我创建了一个简单的测试用例,展示了我在一个更大的代码库中注意到的奇怪行为.这个测试用例如下.我依靠STL Map的"[]"运算符来创建指向这种结构的映射中的结构的指针.在下面的测试用例中,线...
TestStruct *thisTestStruct = &testStructMap["test"];
Run Code Online (Sandbox Code Playgroud)
...给我指针(并在地图中创建一个新条目).我注意到的奇怪之处在于,这一行不仅会导致地图中的新条目被创建(因为"[]"运算符),但由于某种原因,它会导致结构体的析构函数被多次调用两次.我显然错过了一些东西 - 非常感谢任何帮助!谢谢!
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
Run Code Online (Sandbox Code Playgroud)
上面的代码输出以下内容......
/*
Marker One
TestStruct Constructor! //makes sense …Run Code Online (Sandbox Code Playgroud) 2月12日编辑
我最近刚刚使用一些SWIG生成的Python包装器为一些C++类提出了一个奇怪的崩溃.似乎SWIG和Python的结合有点急于清理临时值.事实上,他们非常渴望在他们还在使用的时候进行清理.一个显着浓缩的版本看起来像这样:
/* Example.hpp */
struct Foo {
int value;
~Foo();
};
struct Bar {
Foo theFoo;
Bar();
};
/* Example.cpp */
#include "Example.hpp"
Bar::Bar() {theFoo.value=1;}
Foo::~Foo() {value=0;}
/* Example.i */
%module Example
%{
#include "Example.hpp"
%}
%include "Example.hpp"
Run Code Online (Sandbox Code Playgroud)
我在.i文件上运行SWIG(1.3.37),然后在Python中运行:
Python 2.4.3 (#1, Sept 17 2008, 16:07:08)
[GCC 4.1.2 20071124 (Red Hat 4.1.2-41)] on linux2
Type "help", "copyright", "credits", or "license" for more information.
>>> from Example import Bar
>>> b=Bar()
>>> print b.theFoo.value # expect '1', since Bar's constructor …Run Code Online (Sandbox Code Playgroud) 代码如下:
#include <vector>
int main()
{
vector<int> v1(5,1);
v1.swap(vector<int> ()); //try to swap v1 with a temporary vector object
}
Run Code Online (Sandbox Code Playgroud)
上面的代码无法编译,错误:
error: no matching function for call to ‘std::vector<int, std::allocator<int> >::swap(std::vector<int, std::allocator<int> >)’
Run Code Online (Sandbox Code Playgroud)
但是,如果我将代码更改为类似的东西,它可以编译:
int main()
{
vector<int> v1(5,1);
vector<int> ().swap(v1);
}
Run Code Online (Sandbox Code Playgroud)
为什么?
我有一个相当基本的C++问题,考虑一个函数,它接受一些输入参数并std::string从这些参数中创建一个,如下所示:
std::string constructString( int some_parameter ) {
std::stringstream ss;
// Construct a string (arbitrarily complex)
ss << "Some parameter is " << some_parameter << " right now";
return ss.str(); //Am I not returning a temporary object here?
}
Run Code Online (Sandbox Code Playgroud)
我知道stringstream-object在函数返回时会超出范围,但是不会使构造的字符串失效吗?
如果我将返回类型更改为const char *并返回,会发生什么ss.str().c_str()?
像上面这样的代码似乎有效,但我怀疑这只是因为当我使用它时,包含'临时'对象的内存还没有被其他东西覆盖?
我不得不承认,在这种情况下我总是很困惑,如果有人可以向我解释这整个"临时对象"(或者只是指向正确的方向),我会很感激.
thx提前
考虑以下示例程序:
#include <iostream>
using namespace std;
struct t
{
~t() {cout << "destroyed\n"; }
};
int main()
{
cout << "test\n";
t(), cout << "doing stuff\n";
cout << "end\n";
}
Run Code Online (Sandbox Code Playgroud)
我从GCC 4.9.2获得的输出是:
test
doing stuff
destroyed
end
Run Code Online (Sandbox Code Playgroud)
cpp.sh链接:http://cpp.sh/3cvm
但是根据关于逗号运算符的cppreference:
在逗号表达式E1,E2中,评估表达式E1,丢弃其结果,并且在评估表达式E2开始之前完成其副作用
我希望~t()以前能打电话给我cout << "doing stuff"
这是标准行为吗?如果是这样,标准中的定义在哪里?
c++ object-lifetime comma-operator language-lawyer temporary-objects
我有一个现有的功能:
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)
但是这个对象不会被删除.
下面的代码导致未定义的行为,如果按原样使用:
vector<int> vi;
...
vi.push_back(1); // thread-1
...
vi.pop(); // thread-2
Run Code Online (Sandbox Code Playgroud)
传统的方法是修复它std::mutex:
std::lock_guard<std::mutex> lock(some_mutex_specifically_for_vi);
vi.push_back(1);
Run Code Online (Sandbox Code Playgroud)
但是,随着代码的增长,这样的事情开始变得麻烦,因为每次在方法之前都会有锁.而且,对于每个对象,我们可能必须保持互斥锁.
在不影响访问对象和声明显式互斥体的语法的情况下,我想创建一个模板,使其完成所有样板工作.例如
Concurrent<vector<int>> vi; // specific `vi` mutex is auto declared in this wrapper
...
vi.push_back(1); // thread-1: locks `vi` only until `push_back()` is performed
...
vi.pop () // thread-2: locks `vi` only until `pop()` is performed
Run Code Online (Sandbox Code Playgroud)
在当前的C++中,实现这一目标是不可能的.不过,我试图在那里,如果只是改变代码vi.来vi->,然后按预期在上面的代码中的注释工作的事情.
// The `Class` member is accessed via `->` instead of `.` operator
// For `const` object, it's assumed …Run Code Online (Sandbox Code Playgroud) 考虑以下代码:
void foo() {
int arr[1];
*arr; // OK
using T = int[1];
*T{}; // OK for Clang and MSVC
// GCC error: taking address of temporary array
}
Run Code Online (Sandbox Code Playgroud)
在 Compiler Explorer 中查看实时代码。
我的直觉是,这*T{}应该会导致数组到指针的转换,并且间接寻址的格式良好。不过,我对此并不完全确定。
GCC 是对的还是这是一个错误?是故意的,为了防止开发人员犯错误吗?毕竟,您通常不会取消引用数组。这有记录在任何地方吗?
| 免责声明 |
|---|
CWG Issue 2548已确认“通过数组纯右值的间接寻址现在也无效”。@StoryTeller 的答案是错误的,并通过假设这也适用于 来误解目标类型*T{}的含义,但该表达式不是指针的初始化。 |
更多讨论请参见编辑问题EDIT 6555