我想使用std::atomic_int变量.在我的代码中,我有:
#include <atomic>
std::atomic_int stop = 0;
int main()
{
// Do something
}
Run Code Online (Sandbox Code Playgroud)
这给了我一个编译错误:
use of deleted function 'std::__atomic_base<_IntTp>::__atomic_base(const std::__atomic_base<_IntTp>&) [with _ITp = int]'
std::atomic_int stop = 0;
^
Run Code Online (Sandbox Code Playgroud)
对于发生了什么有什么想法?
它在[C++ 11:12.8/31]中说明:
复制/移动操作的省略,称为复制省略,允许[...]:
- 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(除函数或catch子句参数之外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
这意味着
#include <iostream>
using namespace std;
struct X
{
X() { }
X(const X& other) { cout << "X(const X& other)" << endl; }
};
X no_rvo(X x) {
cout << "no_rvo" << endl;
return x;
}
int main() {
X x_orig;
X x_copy = no_rvo(x_orig);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将打印
X(const X& other)
no_rvo
X(const X& other)
Run Code Online (Sandbox Code Playgroud)
为什么需要第二个拷贝构造函数?编译器不能简单地延长x的生命周期吗?
假设我们有这个类:
class X {
public:
explicit X (char* c) { cout<<"ctor"<<endl; init(c); };
X (X& lv) { cout<<"copy"<<endl; init(lv.c_); };
X (X&& rv) { cout<<"move"<<endl; c_ = rv.c_; rv.c_ = nullptr; };
const char* c() { return c_; };
private:
void init(char *c) { c_ = new char[strlen(c)+1]; strcpy(c_, c); };
char* c_;
};
Run Code Online (Sandbox Code Playgroud)
以及此示例用法:
X x("test");
cout << x.c() << endl;
X y(x);
cout << y.c() << endl;
X z( X("test") );
cout << z.c() << endl;
Run Code Online (Sandbox Code Playgroud)
输出是:
ctor …Run Code Online (Sandbox Code Playgroud) 可能重复:
什么是复制省略和返回值优化?
我很难理解为什么在下面的代码中没有调用复制构造函数.
#include <iostream>
class Test
{
public:
Test(int){std::cout << "Test()" << std::endl;}
Test(const Test&){std::cout << "Test(const Test&)" << std::endl;}
};
int main()
{
// Test test;
Test test2(Test(3));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么只调用构造函数而没有复制构造函数?
谢谢.
我读到模板copy-con永远不是默认的onstructor,而模板赋值操作永远不是复制赋值操作符.
我无法理解为什么需要这个限制并立即上线到ideone并返回一个测试程序但是这里复制构造函数永远不会被调用进一步的谷歌搜索我遇到了模板化的构造函数并尝试了但仍然从未调用复制构造函数.
#include <iostream>
using namespace std;
template <typename T> class tt
{
public :
tt()
{
std::cout << std::endl << " CONSTRUCTOR" << std::endl;
}
template <typename U> const tt<T>& operator=(const tt<U>& that){std::cout << std::endl << " OPERATOR" << std::endl;}
template <typename U> tt(const tt<U>& that)
{
std::cout << std::endl << " COPY CONSTRUCTOR" << std::endl;
}
};
tt<int> test(void)
{
std::cout << std::endl << " INSIDE " << std::endl; tt<int> a; return a;
}
int main() …Run Code Online (Sandbox Code Playgroud) struct X {
X (int x) {}
};
int main() {
X x1(0); // nothing!
X x2 = 0; // warning: unused variable
X x3 = X(0); // warning: unused variable
}
Run Code Online (Sandbox Code Playgroud)
为什么没有生成警告x1?
我正在编译-Wall选项.
GCC和Clang都产生相同的输出.
这3行生成相同的汇编指令(asm("nop")为清楚起见放置一些):
nop
lea -0x8(%rbp),%rdi
mov $0x0,%esi
callq 400600 <X::X(int)>
nop
lea -0x10(%rbp),%rdi
mov $0x0,%esi
callq 400600 <X::X(int)>
nop
lea -0x18(%rbp),%rdi
mov $0x0,%esi
callq 400600 <X::X(int)>
nop
Run Code Online (Sandbox Code Playgroud)原始类型(例如,typedef int X)不会发生这种情况.
如果原因涉及构造函数中可能存在副作用的事实,则问题变为:为什么我会得到另外两个警告?
我想在某个地方有一个答案,但我找不到它,因为有很多线程问题,相比之下,我的相当简单.
我不是要创建线程安全的副本或赋值构造函数或类似的东西.
我想知道的是,如果我有一个表示互斥锁的类,并且我从一个实例化它的函数返回,这首先发生,我的互斥体的析构函数(因此解锁它)或返回值的复制构造函数.这是我的例子:
string blah::get_data(void)
{
MutexLock ml(shared_somewhere_else); // so this locks two threads from calling get_data at the same time
string x = "return data";
return x;
}
Run Code Online (Sandbox Code Playgroud)
在其他地方,我们称之为get_data ...
string result = get_data();
Run Code Online (Sandbox Code Playgroud)
回想一下C,我们永远不会返回指向全局变量的指针,因为返回后局部变量超出了范围.
C++没有这个问题,因为x会被复制到结果中.我想知道的是什么时候发生.在复制之前我的锁是免费的吗?
在这个简单的例子中,"返回数据"是静态信息,但我正在使用它,它的数据可以由另一个线程更改(也锁定在同一个MutexLock上),所以如果锁在释放之前释放了复制到结果制作,副本可能会被破坏.
我不确定我是否正在解释这个问题,所以我会试着澄清这是否有意义.
所以我学习了构造函数初始化列表,并编写了以下代码:
class Mango
{
public:
Mango(){cout<<"Mango::ctor()";}
Mango(const Mango& other){cout<<"Mango::copy_ctor()";}
};
class Box
{
public:
Box() : mango(Mango()) //**doesn't call copy constructor**
{
}
Mango mango;
};
int main()
{
Box box;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我为此使用了g ++编译器.它调用构造函数而不是复制构造函数.它应该调用复制构造函数,因为我正在创建一个对象来创建另一个对象?这里有什么问题,标准说了什么?
说我有struct这样的:
struct S
{
int i;
double d;
std::string s;
};
Run Code Online (Sandbox Code Playgroud)
我可以这样做吗?
std::make_shared<S>(1, 2.1, "Hello")
Run Code Online (Sandbox Code Playgroud) 你好 stackoverflow 社区,
我已经学习 C++ 几个月了,最近我一直在尝试掌握围绕“新”值类别、移动语义,尤其是临时物化的概念。
首先,如何解释“临时物化转换”这个词对我来说并不简单。转换部分对我来说很清楚(prvalue -> xvalue)。但在这种情况下,“临时”究竟是如何定义的呢?我曾经认为临时对象是仅存在的未命名对象 - 从语言的角度来看 - 直到评估它们所创建的表达式的最后一步。但这种概念似乎与临时对象的实际情况不符在临时物化、新价值类别等更广泛的背景下。
由于对“临时”一词缺乏明确性,导致我无法判断“临时物化”是临时物化还是临时物化。我认为是前者,但我不确定。另外:术语“临时”仅用于类类型吗?
这直接给我带来了下一个困惑:prvalues 和 xvalues 对于临时变量起什么作用?假设我有一个右值表达式,需要以必须将其转换为 xvalue 的方式进行计算,例如通过执行成员访问。究竟会发生什么?纯右值是否实际存在(在内存中或其他地方)并且纯右值是否已经是临时的?现在,“临时物化转换”被描述为“任何完整类型 T 的纯右值都可以转换为相同类型 T 的 xvalue。此转换通过使用临时对象评估纯右值,从纯右值初始化类型 T 的临时对象作为其结果对象,并生成一个表示临时对象的 xvalue”(https://en.cppreference.com/w/cpp/language/implicit_conversion)将纯右值转换为 xvalue。这段摘录让我认为纯右值是在内存或寄存器中任何地方都不存在的东西,直到它通过这种转换“具体化”为止。(另外,我不确定临时对象是否与临时对象相同。)因此,据我了解,此转换是通过对纯右值表达式进行求值来完成的,该表达式的结果是“真实”对象。然后,该对象由 xvalue 表达式表示(= 表示?)。记忆中发生了什么?右值在哪里,x值现在在哪里?
我的下一个问题是关于临时物化的某个部分的更具体的问题。在 Kris van Rens 在 YouTube ( https://www.youtube.com/watch?v=liAnuOfc66o&t=3576s ) 上大约 56:30 的演讲“Understanding valuecategories in C++”中,他展示了这张幻灯片:
根据 cppreference.com 关于临时物化的说法,数字 1 和 2 是明确的情况(1:类 pravlue 上的成员访问,2:将引用绑定到纯右值(如 std::string + 运算符中)。
不过,我对第三个不太确定。Cppreference 说:“请注意,当从相同类型的纯右值(通过直接初始化或复制初始化)初始化对象时,不会发生临时物化:此类对象是直接从初始化器初始化的。这确保了“保证复制省略”。 ” + 运算符返回纯右值。现在,这个 std::string 类型的纯右值用于初始化一个 auto(也应该解析为 std::string)变量。这听起来像是前面的 cppreference 摘录中讨论的情况。那么这里真的会出现临时实体化吗?由中间的 xvalue 表达式“表示”的对象(1 和 2)会发生什么情况?他们什么时候被摧毁?如果 + 运算符返回纯右值,它是否“存在”在某个地方?如果纯右值甚至不是真实的(物化?)对象,那么对象 auto …