Non copyable, moveable classes in shared libraries [duplicate] - c++

This question already has answers here:
DLL exporting causing issues with unique pointers
(2 answers)
Compiler error when exporting class
(1 answer)
dllexport a type with a std container of std::unique_ptr results in error C2280
(2 answers)
Closed 18 days ago.
Why am I getting compile errors only when exporting my library? I am not accessing it beyond any shared library boundaries. If I remove the __declspec(dllexport)s, the code compiles just fine.
It's almost like std::vector doesn't support move on exported code?
// Class.h
#pragma once
class __declspec(dllexport) Class
{
public:
// Disable copy semantics
Class(const Class&) = delete;
Class& operator=(const Class&) = delete;
// Enable move semantics
Class(Class&&) noexcept = default;
Class& operator=(Class&&) noexcept = default;
};
// Container.h
#pragma once
#include "Class.h"
#include <vector>
class __declspec(dllexport) Container
{
std::vector<Class> classes;
};
Commenting out __declspec(dllexport) will make the code compile.
The code is compiled using MSVC, ISO c++14, Windows SDK 10.0.
Full compilation output: https://pastebin.com/p1fhxMUp

Related

How to implement static class members in a header-only library? [duplicate]

This question already has answers here:
C++: Header-only project, static const non-integral
(1 answer)
How can you define const static std::string in header file?
(2 answers)
C++ static const string in header c++11
(2 answers)
Closed 2 years ago.
I am implementing a new header-only Library in VS2019, targeting C++11. As discussed (How to initialize a static const member in C++?) you cannot initialize a non-int static class member in-line.
class A {
private:
static const std::string SPECIAL_KEY = "A8787HHH"; //NOT OK
/*...*/
};
Instead you have to define it outside the class, typically in a CPP file:
class A {
private:
static const std::string SPECIAL_KEY;
/*...*/
};
const std::string A::SPECIAL_KEY = "A8787HHH";
But in a header-only library this runs into problems. I tried to do the above all in the same header and it worked in a simple test-app, but in real use I got linker errors that symbol A::SPECIAL_KEY was multiply defined, not surprising really as the header will get included in multiple places (How to initialize private static members in C++?)
In C++17 you can define in-line (https://stackoverflow.com/a/45062055/197229) but that's not any help to me on this code-base. C++ doesn't provide static class constructors either.
Header-only libraries have become quite widely used so is there a standard workaround to what must be a common sort of problem, until such time as we might be able to upgrade to C++17?

Guaranteed copy elision for uniform braced array initialization - Shouldn't this be mandatory since C++17? [duplicate]

This question already has answers here:
How to initialize array of classes with deleted copy constructor (C++11)
(2 answers)
Closed 2 years ago.
As far as I understand the new rules correctly
https://en.cppreference.com/w/cpp/language/copy_elision
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
This code should compile for C++17 standard conform compilers
struct NonTrivialClass
{
~NonTrivialClass( ){ }
};
class MainNonTrivialClass
{
public:
MainNonTrivialClass(int t) : m_simpleTypeMember(t) { }
virtual void makeMySelfNonTrivial() {}
MainNonTrivialClass( const MainNonTrivialClass& other) = delete;
MainNonTrivialClass& operator=( const MainNonTrivialClass& other) = delete;
MainNonTrivialClass(MainNonTrivialClass&& other) = delete;
MainNonTrivialClass& operator=(MainNonTrivialClass&& other) = delete;
NonTrivialClass m_nontrivialMember;
int m_simpleTypeMember;
};
class ArrayContainer
{
public:
ArrayContainer() : m_array{{1}, {2} } {}
private:
MainNonTrivialClass m_array[2];
};
int main()
{
ArrayContainer accContainer;
}
But gcc 9.1.0 with -std=c++17 -O2 -Wall -pedantic says (as totally expected for pre C++17)
main.cpp: In constructor 'ArrayContainer::ArrayContainer()':
main.cpp:25:39: error: use of deleted function 'MainNonTrivialClass::MainNonTrivialClass(MainNonTrivialClass&&)'
25 | ArrayContainer() : m_array{{1}, {2} } {}
| ^
main.cpp:15:3: note: declared here
15 | MainNonTrivialClass(MainNonTrivialClass&& other) = delete;
Array uniform initialization this way is defined as element-wise copy initialization(?) and should lead to copy elision so I do not really understand, what's actually going on here. The old pre C++17 rules seem to be applied here. A further curiosity is, that the same code compiles fine if I remove m_nontrivialMember from my MainNonTrivialClass but shouldn't it lead to the same compile error then always since the non-copy-elision case forces the existence of the according copy/move constructors always?
This should also work pre-C++17, where this syntax is direct-initialization. See How to initialize array of classes with deleted copy constructor (C++11) which refers to GCC bug 63707.

Is the way i declared the Abstract-Class wrong/not common? [duplicate]

This question already has answers here:
Can I use `abstract` keyword in C++ class
(12 answers)
Closed 4 years ago.
I was told, the way I declared the Abstract-Class is wrong or not used in C++ but it still works.
I couldn't find any useful source to create an opinion about this so I want to know if it's unusual/wrong/right to programm it this way.
#pragma once
class TestClass abstract
{
public:
void test();
TestClass();
~TestClass();
};
int main()
{
std::cout << "Hello World!\n";
TestClass baum;
}
Error (active) E0322 An object of type "" TestClass "" of an abstract class is not allowed: test
I can't create any object of "TestClass" so my guess is it works but my teacher told me it's wrong.
There is no explicit keyword to make your class abstract in C++. Your code shouldn't compile because abstract isn't a C++ keyword, you're probably using a compiler extension to not have it trip over that keyword.
The way you create an abstract class in C++ is by declaring one or more pure virtual functions, your test for example:
virtual void test() = 0;

Difference in constructors with X() = delete; and private X(); [duplicate]

This question already has answers here:
Which is the difference between declaring a constructor private and =delete?
(7 answers)
Closed 7 years ago.
Let us assume we have a class X and we want wo explicitly forbid, let say the standard constructor. I used for a long time in the Header file:
private:
X(); // 1.
so, that the contructor was disabled outside the class, so for anybody. But recently I have learned that in C++11 follwoing was recommended:
X() = delete; // 2.
Both would achive my wish to forbid the standard contructor.
But what is the exact difference bewteen them? Why would C++11 recommend the last one? Are there any other flags, signals set in the 2. way?
Example 1 was the way to do it before we had = delete which came out in C++11. Now that we have = delete this will completely get rid of the constructor. With making the constructor private you could still use that constructor in a member function where if you try to default an object in a member function with = delete it will be a compiler error.
#include <iostream>
class Foo
{
Foo();
public:
static void SomeFunc() { Foo f; }
};
class Bar
{
public:
Bar() = delete;
static void SomeFunc() { Bar b; }
};
int main()
{
Foo::SomeFunc(); // will compile
Bar::SomeFunc(); // compiler error
}
Live Example
The former is kind of a hack. A friend class could still call the constructor (and you'd get an error at link-time unless you actually defined it as well).
The latter actually prevents its auto-generation so it's really not there.

Forward declaration with unique_ptr? [duplicate]

This question already has answers here:
Is std::unique_ptr<T> required to know the full definition of T?
(9 answers)
Closed 8 years ago.
I have found it useful to use forward declaration of classes in combination with std::unique_ptr as in the code below. It compiles and works with GCC, but the whole thing seem kind of strange, and I wonder if this is standard behaviour (i.e. required by the standard)? Since B isn't a complete type when I declare the unique_ptr.
A.hpp
#include <memory>
class B;
class A {
std::unique_ptr<B> myptr;
// B::~B() can't be seen from here
public:
~A();
};
A.cpp
#include "B.hpp"
//B.hpp has to be included, otherwise it doesn't work.
A::~A() = default; // without this line, it won't compile
// however, any destructor definiton will do.
I suspect this has to do with the destructor (and therefore the need to call the destructor of unique_ptr<B>) is defined in a specific compilation unit (A.cpp).
It's explicitly legal. The rule is that the types used to instantiate
a template in the standard library must be complete, unless otherwise
specified. In the case of unique_ptr, §20.7.1/5 says “[...] The
template parameter T of unique_ptr may be an incomplete type.”
There are certain operations on the pointer which require a complete
type; in particular, when the object will actually be destructed (at
least with the default deleter). In your example, for example, if
A::~A() were inline, this might cause problems. (Note that if you
don't declare the destructor yourself, it will be inline. Which
partially defeats the purpose of using std::unique_ptr.)