这两个表达式在 C++ 中是否完全相同:"CTest cTest(t);" "CTest cTest=t;"?只是效率不同?
Are these two expresions all the same:"CTest cTest(t);" "CTest cTest=t;" in C++? Only different in efficiency?
作为主题,相关代码已列出below.You可以在https://godbolt.org/z/bcf8js上查看。
毫无疑问 EntityId_t c_SEDSubscribe(ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER);
调用 the user defined constructor EntityId_t(int id)
而我认为 EntityId_t c_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER
;应该调用用户定义的构造函数 EntityId_t(int id)
和移动赋值运算符,但由于终止输出,情况并非如此。
换句话说,我认为 ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER 调用用户定义的构造函数 EntityId_t(int id) 来产生一个临时的 object.Since 它是一个右值(临时对象),编译器然后调用移动赋值 operation.Where 我错了吗?如果能为这个问题提供一些帮助,我将不胜感激。
#include<string.h>
#include<iostream>
#define ENTITYID_UNKNOWN 0x00000000
#define ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER 0x000003c2
#define ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER 0x000003c1
struct EntityId_t
{
static constexpr unsigned int size = 4;
char value[size];
//! Default constructor. Uknown entity.
EntityId_t(){
*this = ENTITYID_UNKNOWN;
}
EntityId_t(int id)
{
int* aux = (int*)(value);
*aux = id;
std::cout << "EntityId_t(int id) constructor" << std::endl;
}
/*!
* @brief Copy constructor
*/
EntityId_t(
const EntityId_t& id)
{
memcpy(value, id.value, size);
std::cout << "copy constructor" << std::endl;
}
EntityId_t& operator =(
const EntityId_t& id)
{
memcpy(value, id.value, size);
std::cout << "copy operator() constructor" << std::endl;
return *this;
}
/*!
* @brief Move constructor
*/
EntityId_t(
EntityId_t&& id)
{
memmove(value, id.value, size);
std::cout << "move constructor" << std::endl;
}
EntityId_t& operator =(
EntityId_t&& id)
{
memmove(value, id.value, size);
std::cout << "move operator(EntityId_t&&)" << std::endl;
return *this;
}
};
int main()
{
EntityId_t c_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER;
std::cout << "==============================" << std::endl;
EntityId_t c_SEDSubscribe(ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER);
}
ClassName var{foo};
这里直接调用构造函数,传入foo
.
ClassName var = foo;
这会尝试将 foo
隐式转换为 ClassName
,并且 要求 这种机制可用。这可能是 ClassName
上的非显式转换构造函数或 foo
类型上的非显式 operator ClassName
。如果找不到这样的隐式转换,这是一个编译时错误。
如果可以找到转换:
- 在 C++17 之前:这将创建一个临时的,然后如果可能的话从它移动构造
var
,或者如果移动构造不可能则复制构造。几乎所有的编译器都会省略 move/copy,但是这样的构造函数仍然需要存在并且可以调用。
- C++17 及更高版本:这实际上与显式初始化形式相同。不需要 move/copy 构造函数可用。
我们可以用一个简单的测试用例来证明这一点:
class Example {
public:
Example(int) {}
Example(Example const &) = delete;
Example(Example &&) = delete;
};
int main() {
Example b = 0;
(void)b; // Just silencing the unused variable warning
}
在 C++14 模式下编译产生:
main.cpp: In function 'int main()':
main.cpp:10:17: error: use of deleted function 'Example::Example(Example&&)'
10 | Example b = 0;
| ^
在 C++17 模式下编译成功,表明没有尝试复制或移动构造。
请注意,由于 operator Example()
出现在源值的类型上,因此转换发生时结果相同。
我post答案被人删了quickly.But我觉得是对的
should call the user defined constructor EntityId_t(int id) and
movement assignment operator
概念上调用构造函数EntityId_t(int id)构造一个临时对象,
用于初始化对象;
在这种情况下,将使用移动构造函数但不使用移动赋值运算符。
由于复制省略,最后一步(移动构造函数调用)
可能会被省略,那么这两种方式都会获得相同的效果:
该对象由构造函数 EntityId_t(int id) 直接初始化。
由于C++17复制省略是强制的,在C++17复制省略是优化之前,即使不调用移动构造函数,它仍然必须可用。
作为主题,相关代码已列出below.You可以在https://godbolt.org/z/bcf8js上查看。
毫无疑问 EntityId_t c_SEDSubscribe(ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER);
调用 the user defined constructor EntityId_t(int id)
而我认为 EntityId_t c_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER
;应该调用用户定义的构造函数 EntityId_t(int id)
和移动赋值运算符,但由于终止输出,情况并非如此。
换句话说,我认为 ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER 调用用户定义的构造函数 EntityId_t(int id) 来产生一个临时的 object.Since 它是一个右值(临时对象),编译器然后调用移动赋值 operation.Where 我错了吗?如果能为这个问题提供一些帮助,我将不胜感激。
#include<string.h>
#include<iostream>
#define ENTITYID_UNKNOWN 0x00000000
#define ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER 0x000003c2
#define ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER 0x000003c1
struct EntityId_t
{
static constexpr unsigned int size = 4;
char value[size];
//! Default constructor. Uknown entity.
EntityId_t(){
*this = ENTITYID_UNKNOWN;
}
EntityId_t(int id)
{
int* aux = (int*)(value);
*aux = id;
std::cout << "EntityId_t(int id) constructor" << std::endl;
}
/*!
* @brief Copy constructor
*/
EntityId_t(
const EntityId_t& id)
{
memcpy(value, id.value, size);
std::cout << "copy constructor" << std::endl;
}
EntityId_t& operator =(
const EntityId_t& id)
{
memcpy(value, id.value, size);
std::cout << "copy operator() constructor" << std::endl;
return *this;
}
/*!
* @brief Move constructor
*/
EntityId_t(
EntityId_t&& id)
{
memmove(value, id.value, size);
std::cout << "move constructor" << std::endl;
}
EntityId_t& operator =(
EntityId_t&& id)
{
memmove(value, id.value, size);
std::cout << "move operator(EntityId_t&&)" << std::endl;
return *this;
}
};
int main()
{
EntityId_t c_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER;
std::cout << "==============================" << std::endl;
EntityId_t c_SEDSubscribe(ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER);
}
ClassName var{foo};
这里直接调用构造函数,传入foo
.
ClassName var = foo;
这会尝试将 foo
隐式转换为 ClassName
,并且 要求 这种机制可用。这可能是 ClassName
上的非显式转换构造函数或 foo
类型上的非显式 operator ClassName
。如果找不到这样的隐式转换,这是一个编译时错误。
如果可以找到转换:
- 在 C++17 之前:这将创建一个临时的,然后如果可能的话从它移动构造
var
,或者如果移动构造不可能则复制构造。几乎所有的编译器都会省略 move/copy,但是这样的构造函数仍然需要存在并且可以调用。 - C++17 及更高版本:这实际上与显式初始化形式相同。不需要 move/copy 构造函数可用。
我们可以用一个简单的测试用例来证明这一点:
class Example {
public:
Example(int) {}
Example(Example const &) = delete;
Example(Example &&) = delete;
};
int main() {
Example b = 0;
(void)b; // Just silencing the unused variable warning
}
在 C++14 模式下编译产生:
main.cpp: In function 'int main()':
main.cpp:10:17: error: use of deleted function 'Example::Example(Example&&)'
10 | Example b = 0;
| ^
在 C++17 模式下编译成功,表明没有尝试复制或移动构造。
请注意,由于 operator Example()
出现在源值的类型上,因此转换发生时结果相同。
我post答案被人删了quickly.But我觉得是对的
should call the user defined constructor EntityId_t(int id) and movement assignment operator
概念上调用构造函数EntityId_t(int id)构造一个临时对象, 用于初始化对象; 在这种情况下,将使用移动构造函数但不使用移动赋值运算符。
由于复制省略,最后一步(移动构造函数调用) 可能会被省略,那么这两种方式都会获得相同的效果: 该对象由构造函数 EntityId_t(int id) 直接初始化。 由于C++17复制省略是强制的,在C++17复制省略是优化之前,即使不调用移动构造函数,它仍然必须可用。