【问题标题】:Error C2280 / Problem with Copy Constructor while instantiating an Object in std::vector?错误 C2280 / 在 std::vector 中实例化对象时复制构造函数出现问题?
【发布时间】:2019-10-09 19:23:08
【问题描述】:

我目前正在按照 ChiliTomatoNoodle 的教程编写我的第一个应用程序,并根据我的需要修改他的代码。在这样做并实现一个简单的 WindowManager 类时,该类的目的是将所有窗口实例存储在 std::vector 和类似的东西中,我收到以下错误消息:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\xmemory(758,1):

错误 C2280: 'Window::Window(const Window &)': 试图引用已删除的函数(编译源文件 src\cpp\WindowManager.cpp)

问题似乎出在addWindow函数中,其中窗口被实例化并存储在std::vector<Window> Wnd中:

void WindowManager::addWindow(unsigned short x, unsigned short y, unsigned short width, unsigned short height, const char* name, Window::WindowClass& windowClass, DWORD style) {

    this->Wnd.emplace_back(Window(name, x, y, width, height, windowClass, style, this->IdGenNum++));
}

我已经将push_back 更改为emplace_back 以避免复制(?),但这并没有解决问题。

然后还有一个getter(看起来很好,不复制任何东西):

Window& WindowManager::getWindow(const unsigned short id) {

    for (Window &element : this->Wnd) {

        if (element.Id == id) {

            return element;
        }
    }
}

这里是Window 类头:

class Window {

private:    // Friends

    friend class WindowManager;

public:     // Nested Classes

    class WindowClass {

        ...
    };

private:    // Variables and Instances

    unsigned short Id;    // Received by WindowManager on Creation

    const char* Name;

    HWND Handle;

    ...

public:     // Constructors and Deconstructors

    Window(const Window&) = delete;

    Window(
        
        const char* name,
        unsigned short x, 
        unsigned short y, 
        unsigned short width, 
        unsigned short height,  
        WindowClass& windowClass, 
        DWORD style,
        unsigned short id
    );

    ~Window();


private:    // Functions

    ...

public:     // Operators

    Window& operator=(const Window&) = delete;
};

编辑:

感谢所有答案和 cmets 指出参数必须直接传递给 emplace_back 方法。事实证明,向量仍然复制了对象(不知道为什么......),但我可以通过使用 std::list 来解决这个问题,它没有这种行为。

【问题讨论】:

  • 为什么是this->Wnd.emplace_back(Window(name, x, y, width, height, windowClass, style, this->IdGenNum++)); 而不是this->Wnd.emplace_back(name, x, y, width, height, windowClass, style, this->IdGenNum++);
  • 因为我认为这是这样做的方法。 ^^' 我认为阅读而不是写作更清晰Window 似乎也解决不了任何问题?还是谢谢!
  • emplace_back() 使用您提供的参数构造向量元素类型。通过将Window(...) 指定为参数,您首先构造了一个临时Window() 对象,然后emplace_back() 尝试使用Window 的复制构造函数在向量内构造另一个Window,该构造函数一直是@987654341 @d。通过省略Window(...),仅在向量内部构造了1 个Window,使用namexy 等变量直接作为该构造函数的参数。
  • @Splize "我认为阅读起来更清晰" 但是,emplace_back 并没有实现它的意图:在向量中创建对象,而不是复制它,正如push_back 所做的那样。由于它会将其参数转发给Window 的构造函数,并且如果它接收到Window const& 类型的单个参数,则匹配该签名的唯一构造函数是复制构造函数。 “似乎也没有解决任何问题” 如果是这种情况,则问题不在emplace_back 调用中。请提供minimal reproducible example
  • push_back() 不必复制。它可以移动。它在 C++11 和更高版本中被重载以接受右值,所以你可以这样做:this->Wnd.push_back(Window(...)); 当然,如果Window 定义了一个移动构造函数会有所帮助。

标签: c++ windows window desktop-application window-managers


【解决方案1】:

Window 复制构造函数是用delete 声明的,但是当您将现有的Window 对象传递给emplace_back() 时,emplace_back() 的实现将尝试使用其参数来构造另一个Window 对象到位。它可以做到这一点的唯一方法是尝试使用已删除的复制构造函数。

您可以声明一个复制构造函数,使用push_back(),或者使用其他Window 构造函数的参数更好地调用emplace_back(),这样可以避免复制。

【讨论】:

    【解决方案2】:

    这一行创建了一个临时窗口,它将被移动(如果有移动构造函数)或复制(如果有复制构造函数)到 vector - 但你的 Window 缺少这两者:

    this->Wnd.emplace_back(Window(name, x, y, width, height, windowClass, style,
                                  this->IdGenNum++));
    

    使用emplace_back,您无需创建临时变量,因为您提供给emplace_back 的参数已完美转发给Window 的构造函数,因此不会进行不必要的移动或复制:

    this->Wnd.emplace_back(name, x, y, width, height, windowClass, style, this->IdGenNum++);
    

    虽然这应该足以解决这个紧迫的问题,但您的 Window 类看起来应该支持移动但不一定支持复制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多