Are these two expresions all the same:"CTest cTest(t);" "CTest cTest=t;" in C++? Only different in efficiency?

0

As the subject, the related code is listed below.You could check it on https://godbolt.org/z/bcf8js.

There is no doubt that EntityId_t c_SEDSubscribe(ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER); calls the user defined constructor EntityId_t(int id) whereas I think EntityId_t c_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER; should call the user defined constructor EntityId_t(int id) and movement assignment operator, but it's not this case since the terminate output. In another word, I think ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER calls the user defined constructor EntityId_t(int id) to produce a temporary object.Since it's a rvalue(temporary object), complier then calls the movement assigment operation.Where am i wrong? I would be grateful to have some help with this question.

    #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);
    }
c++
c++11
constructor
c++17
move-semantics
asked on Stack Overflow Jun 6, 2020 by John

2 Answers

1
ClassName var{foo};

This directly calls the constructor, passing in foo.

ClassName var = foo;

This attempts implicit conversion of foo to ClassName, and requires that such a mechanism be available. This could be a non-explicit conversion constructor on ClassName or a non-explicit operator ClassName on foo's type. If no such implicit conversion can be found, this is a compile-time error.

If a conversion can be found:

  • Before C++17: this will create a temporary and then move-construct var from it if possible, or copy-construct if move-construction is not possible. Pretty much all compilers will elide the move/copy, but such a constructor is still required to exist and be callable.
  • C++17 and later: this is effectively identical to the explicit initialization form. No move/copy constructor is required to be available.

We can prove this with a simple test case:

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
}

Compiling in C++14 mode yields:

main.cpp: In function 'int main()':
main.cpp:10:17: error: use of deleted function 'Example::Example(Example&&)'
   10 |     Example b = 0;
      |                 ^

Compiling in C++17 mode succeeds, indicating that no copy- or move-construction is attempted.

Note that the results are the same when the conversion happens because of an operator Example() present on the source value's type.

answered on Stack Overflow Jun 6, 2020 by cdhowie • edited Jun 6, 2020 by cdhowie
0

I post the answer which has been deleted by somebody quickly.But i think it's right.

should call the user defined constructor EntityId_t(int id) and movement assignment operator

In concept, the constructor EntityId_t(int id) is called to construct a temporary object, which is used to initialize the object; in this case the move constructor would be used but not move assignment operator.

Because of copy elision, the last step (move constructor calling) might be omitted then both two ways get same effect: the object is initialized by the constructor EntityId_t(int id) directly. Since C++17 copy elision is mandatory, before C++17 copy elision is an optimization, even the move constructor is not called, it still must be usable.

answered on Stack Overflow Jun 6, 2020 by John

User contributions licensed under CC BY-SA 3.0