Экспорт DLL вызывает проблемы с уникальными указателями - PullRequest
0 голосов
/ 26 июня 2018

У меня есть два файла:

Header.h

#pragma once

#ifdef UNIQUEPTRISSUE_EXPORTS
#define UNIQUEPTRISSUE_API __declspec(dllexport)   
#else  
#define UNIQUEPTRISSUE_API __declspec(dllimport)   
#endif 

UniquePtrIssue.cpp

#include "stdafx.h"

#include "Header.h"

#include <memory>
#include <vector>

class UNIQUEPTRISSUE_API ClassA {

};

class UNIQUEPTRISSUE_API ClassB {
private:
    std::vector<std::unique_ptr<ClassA>> x;
};

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

1> d: \ program files (x86) \ microsoft visual studio \ 2017 \ enterprise \ vc \ tools \ msvc \ 14.14.26428 \ include \ xutility (2443): ошибка C2280: 'std :: unique_ptr> & std :: unique_ptr <_Ty, std :: default_delete <_Ty >> :: operator = (const std :: unique_ptr <_Ty, std :: default_delete <_Ty >> &)': попытка сослаться на удаленную функцию 1> с помощью 1> [1> _Ty = ClassA 1>]

Подобные проблемы, похоже, возникают при доступе к конструктору копирования unique_ptr, но они некажется, не применяется.

Удаление UNIQUEPTRISSUE_API / __declspec(dllexport) из обоих объявлений классов, похоже, устраняет ошибку.

Очевидно, что с объявлением __declspec(dllexport) что-то происходит, что я не понимаю,Есть ли способ использовать unique_ptr s между экспортируемыми классами?

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

Вы можете выставить класс по-разному:

class ClassB {
private:
    std::vector<std::unique_ptr<ClassA>> x;

public:

    UNIQUEPTRISSUE_API ClassB(ClassB&&) {

    }

    UNIQUEPTRISSUE_API ClassB& operator==(ClassB&&) {

        return* this;

    }

private:

}

, т. Е. Не экспортировать весь класс, а одну функцию.Я пробую это на vs2010 и vs2017

0 голосов
/ 26 июня 2018

Когда вы объявляете класс с declspec(dllexport), компилятор должен сгенерировать все функции-члены класса, включая конструкторы по умолчанию, функции копирования и т. Д., Так как он не знает, какие из них могут понадобиться при импортемодуль.Это описано в Использование dllimport и dllexport в классах C ++ .

Поскольку unique_ptr не может быть скопировано, его конструктор копирования и операторы назначения копирования удаляются, и когда векторный объект пытаетсяиспользуйте их, чтобы получить ошибку C2280.

Если вы не включите declspec(dllexport), компилятор будет генерировать только те функции, которые фактически используются, и проблемных копий не будет.

Одним из способов решения этой проблемы является экспорт отдельных функций-членов класса, что может означать указание некоторых из них по умолчанию.virtual Функции не нужно экспортировать, так как они обрабатываются виртуальной таблицей.

Другой обходной путь - явное удаление конструктора копирования и оператора назначения копирования.Так как это предотвратит создание конструктора по умолчанию и переместит функции конструктора / присваивания, вам может потребоваться использовать их по умолчанию.

class UNIQUEPTRISSUE_API ClassB {
public:
    ClassB(const ClassB &) = delete;
    ClassB &operator=(const ClassB &) = delete;
    // You may need to explicitly default these if they are used
    ClassB() = default;
    ClassB &operator=(ClassB &&) = default;
    ClassB(ClassB &&) = default;
private:
    std::vector<std::unique_ptr<ClassA>> x;
};
...