extern template DLLs and programs (crypto++) - visual-c++

I've been using Crypto++ with VS2005 and VS2010 for a while now. But recently I needed to use it with and application directly. The same code compiles fine when I'm compiling as a DLL and does not compile when compiling as an application.
This is the smallest sample that reproduces the error is this (based on cryptopp561\algparam.h:301 CryptoPP::AlgorithmParametersTemplate
class Base
{
protected:
virtual void MoveInto(void *p) const = 0;
};
template<class T>
class Test: public Base
{
public:
void MoveInto(void * buffer) const
{
Test<T> *x = new(buffer) Test<T>(*this);
}
};
extern template class Test<bool>;
The compilation parameters are the same, only difference that I saw was the configuration type in the project ("Application (.exe)" generates the error and "Dynamic Library (.dll)" does not).
This is the compiler error:
main.h(15): error C2061: syntax error : identifier 'buffer'
main.h(14) : while compiling class template member function 'void Test<T>::MoveInto(void *) const'
with
[
T=bool
]
main.h(20) : see reference to class template instantiation 'Test<T>' being compiled
with
[
T=bool
]
It seems to occur only when theres inheritance. Ommiting : public Base in the class Test declaration makes the error go away.
EDIT:
The problem was in a header included somewhere that defined a a debug version for operator new but didn't declared the placement new version.

Did you #include <new>, the header file that declares placement-new?

Funnily, extern templates are to tell the compiler to not instantiante at some point, so the second error does not make sense to me. Are you certain your compiler has support for extern templates? What if you do the opposite, explicit instantiation:
template class Test<bool>;

Related

Visual C++ lambdas always output debug information

If I instantiate a lambda somewhere (and the compiler doesn't inline it), I can find a string showing where the lambda is located in my c++ code like this:
... ?AV<lambda_1>#?0??MyFunction#MyScopedClass#MyNamespace##SAXXZ# ...
I don't want this information in the executable, as it could give away important names of classes and functions.
All kinds of output debug information are turned off. If I use a normal function instead, the final executable doesn't have this information, so manually converting all lambdas into normal functions would "fix it". But what's the best way to handle this? Can we tell the compiler to transform lambdas into normal functions?
UPDATE: I tested with other compilers: g++ and clang. They both leave the same references. I also found another unanswered question about this Gcc - why are lambdas not stripped during release build Please don't come with the "why do you care about a few symbols anyway".
Here's some code you can test with:
#include <iostream>
#include <functional>
class MyUnscopedClass
{
public:
MyUnscopedClass(const std::function<void(int x)>& f) :
f(f)
{
}
std::function<void(int x)> f;
};
namespace MyNamespace
{
class MyScopedClass
{
public:
static void temp1(int x)
{
std::cout << x * (x + 1);
}
static void MyFunction()
{
//MyUnscopedClass obj(temp1); // no symbols
MyUnscopedClass obj([](int x) // ?AV<lambda_1>#?0??MyFunction#MyScopedClass#MyNamespace##SAXXZ#
{
std::cout << x;
});
obj.f(23);
}
};
}
int main()
{
MyNamespace::MyScopedClass::MyFunction();
}
With the help of #dxiv in the comments, I found the problematic setting.
Configuration Properties > General > C++ Language Standard
can't be, for some reason,
Preview - Features from the Latest C++ Working Draft (std:c++latest)
So I set it to the second most recent one
ISO C++17 Standard (std:c++17)
and I get a random identifier instead.
AV<lambda_f65614ace4683bbc78b79ad57f781b7f>##
I'm still curious how this identifier is chosen though.

Compile error when try to create singleton using shared_ptr

I try to create a singleton object using shared_ptrs. However the code does not compile when the constructors/destructor are private for the specific object
The code is below.h
//ThreadPool.h
class ThreadPool
{
public:
static std::shared_ptr<ThreadPool> & getInstance();
inline static std::shared_ptr<ThreadPool> m_threadPoolInstance;
private:
ThreadPool() =default;
~ ThreadPool() = default;
ThreadPool(ThreadPool const &) = default;
};
//ThreadPool.cpp
#include "pch.h"
#include <ThreadPool.h>
std::shared_ptr<ThreadPool> & ThreadPool::getInstance()
{
if (! m_threadPoolInstance)
{
ThreadPool * p_ThreadPool = new ThreadPool();
m_threadPoolInstance.reset(p_ThreadPool);
}
return m_threadPoolInstance;
}
I am using VS17 compiler
The error that is created is the following
error C2440: '': cannot convert from '_Ux *' to
'std::shared_ptr'
with
[
_Ux=ThreadPool
] include\memory(1462): note: No constructor could take the source type, or constructor overload resolution was ambiguous
threadpool.cpp(9): note: see reference to function template
instantiation 'void std::shared_ptr::reset(_Ux
*)' being compiled
with
[
_Ux=ThreadPool
] threadpool.cpp(9): note: see reference to function template instantiation 'void std::shared_ptr::reset(_Ux
*)' being compiled
with
[
_Ux=ThreadPool
]
When I set the constructors/destructor in public section, the compilation is succesfull.
However running the same code using gcc compiler , compiles succesfully
The conversion fails because your ThreadPool class has a private destructor.
Calling .reset(ptr) will use the delete expression (delete ptr;) as the deleter, which requires that the destructor be public.
Refer to overload (2) here: https://en.cppreference.com/w/cpp/memory/shared_ptr/reset
2-4) Replaces the managed object with an object pointed to by ptr. Y must be a complete type and implicitly convertible to T. Additionally:
2) Uses the delete expression as the deleter. A valid delete expression must be available, i.e. delete ptr must be well formed, have well-defined behavior and not throw any exceptions. Equivalent to shared_ptr(ptr).swap(*this);.
You either need to make the destructor public or provide a custom deleter.

Unable to initialize static set of strings inside templatized class in CLang, works fine in GCC

I'm using Boost config_file_iterator to parse a parameters file for different modules in the standard Boost way:
[Module 1 name]
M1_Key1=value1
[Module 2 name]
M2_Key1=value2
For that, Boost has the nice feature to accept a std::set containing all the valid keys, to throw an exception in case a non-valid one is passed.
boost::program_options::detail::config_file_iterator cfgIt(configStream, ALLOWED_PARAMS);
In my code, I've a set of modules, each one with its own set of parameters, In each one of the module header I have (as non-member variables):
module1.h:
static const std::string MODULE1_NAME = "Module 1 name";
static const std::string MODULE1_KEY1 = "M1_Key1";
module2.h:
static const std::string MODULE2_NAME = "Module 2 name";
static const std::string MODULE2_KEY1 = "M2_Key1";
In the header file for the parameters parser:
class ParametersParser
{
static const std::set<std::string> ALLOWED_PARAMS;
}
Finally in the source file of that parameter parser groups all the allowed values for the config iterator from the different modules:
#include "module1.h"
#include "module2.h"
const std::set<std::string> ParametersParser::ALLOWED_PARAMS =
{{
MODULE1_NAME + std::string(".") + MODULE1_KEY1,
MODULE2_NAME + std::string(".") + MODULE2_KEY1
}};
since Boost expects that as the allowed parameters set, a set of string of the way "Module X Name.MX_KeyY", and that worked fine.
However, because of other reasons, I've templatized the class that parses the file, so now my set of strings is declared also in the same header file, as:
#include "module1.h"
#include "module2.h"
/* Class definition */
template <class T>
class ParametersParser
{
static const std::set<std::string> ALLOWED_PARAMS;
};
/* Static member initialization */
template <class T>
const std::set<std::string> ParametersParser<T>::ALLOWED_PARAMS =
{{
MODULE1_NAME + std::string(".") + MODULE1_KEY1,
MODULE2_NAME + std::string(".") + MODULE2_KEY1
}};
And here is where the problem arises: This compiles in both gcc 4.8.5 (CentOS 7.5 vanilla) and AppleClang 9.1.0.9020039 (MacOSX 10.3), but in MacOSX, the resulting set only contains a ".". It's like the static strings defined in the modules headers (MODULE1_NAME, MODULE1_KEY1, etc) are empty!!! In gcc/CentOS, it works fine. Unfortunately, I couldn't compile on gcc for MacOSX (It complains about unresolved dependencies with Boost), while CLang on CentOS (Apple LLVM version 9.1.0 (clang-902.0.39.2)) works fine too.
Do you have any clues what am I doing wrong? Is it something about using strings as static variables? I also tried declaring the set using the new initializer list syntax, const std::set<std::string> ParametersParser<T>::ALLOWED_PARAMS{{...}}, but didn't work either.
Thanks a lot for your help.

VTable Not Generated

First of all, thank you very much for taking the time to look at my question. Second, I have read this and my class does not have any virtual methods I am forgetting to include. I'll go over additional things I have tried after I describe my problem.
I am getting an undefined reference to `vtable for SubcomponentTypeWidget' error when I build my code using gcc version 3.4.6 20060404. Visual Studio 2005 has no issues. I love Linux, but my current political situation has delegated it to the red headed step child that regularly suffers abuse. Hopefully by our powers combined, I can remedy that.
I am using Qt version 4.6.2. I am using gcc 3.4.6 20060404 on Red Hat 4.
This is my header:
#ifndef SubcomponentTypeWidget_h
#define SubcomponentTypeWidget_h
#include <vector>
#include "ui_SubcomponentTypeWidget.h"
#include "Subcomponent.h"
class SubcomponentTypeWidget : public QWidget, public Ui::SubcomponentTypeWidget
{
Q_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle)
public:
SubcomponentTypeWidget(QWidget* parent,
Models::Subcomponent::SubcomponentType subcomponentType = Models::Subcomponent::kSolid)
: QWidget(parent),
m_subcomponentType(subcomponentType),
m_subcomponentTypeButtonGroup(new QButtonGroup(this))
{
this->initialize();
}
Models::Subcomponent::SubcomponentType subcomponentType() const { return m_subcomponentType; }
void setSubcomponentType(Models::Subcomponent::SubcomponentType type);
void setNonCompatibleTypes(const std::vector<Models::Subcomponent::SubcomponentType>& types);
QString title() const { return m_subcomponentGroupBox->title(); }
void setTitle(const QString &title) { m_subcomponentGroupBox->setTitle(title); }
signals:
void subcomponentTypeChanged();
protected slots:
void handleSubcomponentTypeChoice(int subcomponentTypeChoiceId);
protected:
void initialize();
Models::Subcomponent::SubcomponentType m_subcomponentType;
QButtonGroup* m_subcomponentTypeButtonGroup;
};
#endif // SubcomponentTypeWidget_h
The implementation is here:
#include "SubcomponentTypeWidget.h"
void SubcomponentTypeWidget::setSubcomponentType(Models::Subcomponent::SubcomponentType type)
{
if (type != m_subcomponentType)
{
m_subcomponentType = type;
emit subcomponentTypeChanged();
}
}
void SubcomponentTypeWidget::setNonCompatibleTypes(const std::vector<Models::Subcomponent::SubcomponentType>& types)
{
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kSolid) + 1)->setEnabled(true);
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kComplement) + 1)->setEnabled(true);
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kHole) + 1)->setEnabled(true);
for (std::vector<Models::Subcomponent::SubcomponentType>::const_iterator it = types.begin(); it != types.end(); ++it)
{
m_subcomponentTypeButtonGroup->button(static_cast<int>(*it) + 1)->setEnabled(false);
if (*it == m_subcomponentType)
m_subcomponentTypeButtonGroup->button(static_cast<int>(Models::Subcomponent::kSolid) + 1)->setChecked(true);
}
}
void SubcomponentTypeWidget::handleSubcomponentTypeChoice(int subcomponentTypeChoiceId)
{
if (static_cast<Models::Subcomponent::SubcomponentType>(subcomponentTypeChoiceId - 1) != m_subcomponentType)
{
m_subcomponentType = static_cast<Models::Subcomponent::SubcomponentType>(subcomponentTypeChoiceId - 1);
emit subcomponentTypeChanged();
}
}
void SubcomponentTypeWidget::initialize()
{
this->setupUi(this);
m_subcomponentTypeButtonGroup->addButton(m_solidRadioButton, static_cast<int>(Models::Subcomponent::kSolid) + 1);
m_subcomponentTypeButtonGroup->addButton(m_complementRadioButton, static_cast<int>(Models::Subcomponent::kComplement) + 1);
m_subcomponentTypeButtonGroup->addButton(m_holeRadioButton, static_cast<int>(Models::Subcomponent::kHole) + 1);
m_subcomponentTypeButtonGroup->button(static_cast<int>(m_subcomponentType) + 1)->setChecked(true);
connect(m_subcomponentTypeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(handleSubcomponentTypeChoice(int)));
}
The actual error messages I am receiving are:
../lib/libMeshAndGeometry.a(AddAdvancedDialog.o)(.gnu.linkonce.t._ZN20Ui_AddAdvancedDialog7setupUiEP7QDialog+0x955): In function `Ui_AddAdvancedDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddAdvancedDialog.o)(.gnu.linkonce.t._ZN20Ui_AddAdvancedDialog7setupUiEP7QDialog+0x960): In function `Ui_AddAdvancedDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddAdvancedDialog.o)(.gnu.linkonce.t._ZN20Ui_AddAdvancedDialog7setupUiEP7QDialog+0x99b): In function `Ui_AddAdvancedDialog::setupUi(QDialog*)':
: undefined reference to `SubcomponentTypeWidget::initialize()'
../lib/libMeshAndGeometry.a(AddBoxDialog.o)(.gnu.linkonce.t._ZN15Ui_AddBoxDialog7setupUiEP7QDialog+0xfe8): In function `Ui_AddBoxDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddBoxDialog.o)(.gnu.linkonce.t._ZN15Ui_AddBoxDialog7setupUiEP7QDialog+0xff3): In function `Ui_AddBoxDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddBoxDialog.o)(.gnu.linkonce.t._ZN15Ui_AddBoxDialog7setupUiEP7QDialog+0x102e): In function `Ui_AddBoxDialog::setupUi(QDialog*)':
: undefined reference to `SubcomponentTypeWidget::initialize()'
../lib/libMeshAndGeometry.a(AddConeDialog.o)(.gnu.linkonce.t._ZN16Ui_AddConeDialog7setupUiEP7QDialog+0x7ef): In function `Ui_AddConeDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddConeDialog.o)(.gnu.linkonce.t._ZN16Ui_AddConeDialog7setupUiEP7QDialog+0x7fa): In function `Ui_AddConeDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddConeDialog.o)(.gnu.linkonce.t._ZN16Ui_AddConeDialog7setupUiEP7QDialog+0x835): In function `Ui_AddConeDialog::setupUi(QDialog*)':
: undefined reference to `SubcomponentTypeWidget::initialize()'
../lib/libMeshAndGeometry.a(AddCylinderDialog.o)(.gnu.linkonce.t._ZN20Ui_AddCylinderDialog7setupUiEP7QDialog+0x9c4): In function `Ui_AddCylinderDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddCylinderDialog.o)(.gnu.linkonce.t._ZN20Ui_AddCylinderDialog7setupUiEP7QDialog+0x9cf): In function `Ui_AddCylinderDialog::setupUi(QDialog*)':
: undefined reference to `vtable for SubcomponentTypeWidget'
../lib/libMeshAndGeometry.a(AddCylinderDialog.o)(.gnu.linkonce.t._ZN20Ui_AddCylinderDialog7setupUiEP7QDialog+0xa0a): In function `Ui_AddCylinderDialog::setupUi(QDialog*)':
All of my makefiles have been generated from my .pro file using qmake. The main make files, the main .pro file, and the widgets and MeshAndGeometry make and .pro files are attached here as an archive. One of the .ui files is attached here.
I have tried a number of things.
I am sure this is not a stale object file issue. I have built this from scratch and I still have the the problem.
I checked all of my capitalization issues. One of the problems I have noticed with doing most of this on Windows and then moving it to Linux is that people make mistakes with capitalization, and Windows doesn't care about capitalization.
I ran nm -a -C SubcomponentTypeWidget.o to see if the necessary vtable was there, and it wasn't. However, the 'missing' methods were there.
Creating a virtual destructor does not force vtable generation for SubcomponentTypeWidget.
I have tried removing large chunks of SubcomponentTypeWidget's functionality. This results in removing the specific linker error messages for methods, but it does not remove the undefined reference to vtable message. I have removed everything from SubcomponentTypeWidget other than the constructor, and in this case I still receive the "undefined reference to vtable" message, but without any mention to specific methods we are looking for.
Changing the order of which widgets and MeshingAndGeometry are linked in does not help.
I have tried gcc versions 3.4.6 20060404 and 4.1.2 20080704.
Help me, Obi-Wan Kenobi. You're my only hope.
Thank you all very, very much,
-Brian J. Stinar-
went through your codes the error most likely arises from the following statement:
=======================================================
void SubcomponentTypeWidget::initialize()
{
this->setupUi(this);
//rest of codes
}
=======================================================
you are sort of breaking the structure of Qt by making SubcomponentTypeWidget a subclass of Ui::SubcomponentTypeWidget. You are actually using yourself to setup a UI of yourself in this case. Coupled that with the fact that you are using multiple class inheritance, you are just confusing the compiler on which virtual method to refer to during runtime.
Instead of subclassing Ui::SubcomponentTypeWidget, just make it a private variable in SubcomponentTypeWidget
//SubcomponentTypeWidget.h
private:
Ui::SubcomponentTypeWidge ui;
implement the following in your init function and you should be good to go
void SubcomponentTypeWidget::initialize()
{
ui.setupUi(this);
//rest of codes
}
My problem was with solution point number six. I actually did NOT change this order correctly. I was changing the order in the INCPATH instead of the order in the LIBS.
After adding the line MeshAndGeometry.depends = widgets to my master.pro file, running qmake, and running make, this problem went away.
Thank everyone very much for their comments and help.
-Brian J. Stinar-

inserting "this" into an STL map from the constructor

VERSION 1
class Doh {
private:
static std::map<const std::string, const Doh*> someMap;
std::string stringValue_;
public:
Doh(std::string str) : stringValue_(str) {
Doh::someMap.insert(
std::make_pair<const std::string,const Doh*>
(this->stringValue_,this)
);
}
}
The above was ok with MSVC 2010 but with MSVC 2008 it fails – and I guess it is because the object is not constructed yet when it is inserted in the map (I got a memory access violation).
So, I tried a delayed insertion, which worked:
VERSION 2
Doh(std::string str) : stringValue_(str) {
boost::thread(&Doh::insertIntoTheStaticMap,this);
}
void insertIntoTheStaticMap() {
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
Doh::someMap.insert(
std::make_pair<const std::string,const Doh*>
(this->stringValue_,this)
);
}
But as you might be able to guess, my intention is to have the static Doh::someMap as a common lookup dictionary.
VERSION 1 didn’t need any thread-safety because I would create all Doh instances in the same thread – in initialization blocks - which would be called by dynamic initializers before I enter main().
But with VERSION 2, the naïve sleep() is neither graceful nor reliable (not to mention, I might need to lock the map before insertion).
What would be a nice KISS approach?
Only potential issue I see is the initialization of the static member, if there are multiple source files. Try guarding it with a function.
class Doh {
private:
static std::map< std::string, Doh * > &get_map() {
static std::map< std::string, Doh * > someMap;
return someMap; // initialize upon first use
}
std::string stringValue_;
public:
Doh(std::string str) : stringValue_(str) {
get_map().insert(
std::make_pair
(this->stringValue_,this)
);
}
};
In neither version is there any sign of init for stringvalue_ - what does the debugger show you about this key when you hit the map insert in version 1 of the code? How is this field set up, and what is its type?
Running this in the debugger for VS2008 should allow you to narrow down the point of failure into the <map> source, I would have thought.

Resources