Переместить конструктор, казалось бы, не выполняется - PullRequest
12 голосов
/ 22 января 2011

Это мой первый эксперимент с C ++ 0x rvalue-ссылками, и кажется, что происходит что-то странное.

В примере кода ниже заводской функции MakeWindow возвращает объект Window по значению.Вызывающая сторона использует его для инициализации объекта Window.Если я правильно понял, это должно вызвать конструктор перемещения.Чтобы обнаружить это, я выбрасываю исключение.Кроме того, я отключил конструктор копирования:

#include <iostream>


// Fake WinAPI
typedef void* HWND;
HWND CreateWindow() { return (void*)1; }
void DestroyWindow(HWND) { }
// End WinAPI


// C++ WinAPI Wrapper Library
class Window
{
public:
    Window(HWND inHandle) :
        mHandle(inHandle)
    {
        std::cout << "Window constructor. Handle: " << inHandle << std::endl;
    }

    Window(Window && rhs) :
        mHandle(rhs.mHandle)
    {
        std::cout << "Window move constructor. Handle: " << mHandle << std::endl;
        rhs.mHandle = 0;
        throw 1; // this is my "breakpoint"
    }

    ~Window()
    {
        std::cout << "Window destructor. Handle: " << mHandle << std::endl;
        if (mHandle)
        {
            DestroyWindow(mHandle);
        }
    }

private:
    Window(const Window&);
    Window& operator=(const Window&);

    HWND mHandle;
};


// Factory function
Window MakeWindow()
{
    return Window(CreateWindow());
}


int main()
{

    {
        Window window(MakeWindow());
    }
    std::cout << "Everything is OK." << std::endl;
    return 0;
}

Однако код работает нормально, без этого исключения.Это вывод консоли:

Window constructor. Handle: 0x1
Window destructor. Handle: 0x1
Everything is OK.

Если я закомментирую конструктор перемещения, произойдет сбой компиляции со следующими ошибками:

MysteryMove.cpp: In function 'Window MakeWindow()':
MysteryMove.cpp:39:5: error: 'Window::Window(const Window&)' is private
MysteryMove.cpp:49:33: error: within this context
MysteryMove.cpp: In function 'int main()':
MysteryMove.cpp:39:5: error: 'Window::Window(const Window&)' is private
MysteryMove.cpp:57:35: error: within this context
make: *** [all] Error 1

Это не имеет смысла.Кто-нибудь может объяснить, что происходит?

Обновление

Благодаря @Philipp я узнал, что конструкторы перемещения также можно опустить.Это описано в §12.8 / 34 и сноске 124 проекта стандарта N3126 .

Там также упоминается, что RVO разрешено только для энергонезависимых объектов.Это означает, что я могу обойти это, написав заводскую функцию следующим образом:

// Factory function
Window MakeWindow()
{
    volatile Window window(CreateWindow());
    return const_cast<Window&&>(window);
}

И действительно, это работает:

Window constructor. Handle: 0x1
Window move constructor. Handle: 0x1
terminate called after throwing an instance of 'int'
Abort trap

1 Ответ

9 голосов
/ 22 января 2011

Разве это не очевидно? Ваш код возвращает копию локального временного Window:

Window MakeWindow()
{
    return Window(CreateWindow());
}

Компилятор фактически оптимизирует эту копию (с помощью оптимизации возвращаемого значения) - вот почему ваш конструктор перемещения никогда не вызывается - но для правильности конструктор копии все еще должен присутствовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...