这两个表达式在 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复制省略是优化之前,即使不调用移动构造函数,它仍然必须可用。