TBB compiler error - 'my_task': references must be initialized - c++

I use TBB at multiple places in my project. But it seems that since I update Visual Studio from 15.6.X (X beeing the latest version) to 15.7.1 I get a compiler error at several places, telling me
[...]tbb\task_group.h(94): error C2530: 'my_task': references must be initialized
Looking at the referenced code (tbb/task_group.h):
//! Base class for types that should not be assigned.
class no_assign {
// Deny assignment
void operator=( const no_assign& );
public:
#if __GNUC__
//! Explicitly define default construction, because otherwise gcc issues gratuitous warning.
no_assign() {}
#endif /* __GNUC__ */
};
//! Base class for types that should not be copied or assigned.
class no_copy: no_assign {
//! Deny copy construction
no_copy( const no_copy& );
public:
//! Allow default construction
no_copy() {}
};
// ...
class ref_count_guard : internal::no_copy {
task& my_task; // compiler error occurs here
public:
ref_count_guard( task& t ) : my_task(t) {
my_task.increment_ref_count();
}
~ref_count_guard() {
my_task.decrement_ref_count();
}
};
I don't see why the compiler is complaining there, as the reference is initialized by the constructor. Finding the problem in my code is also not that easy, because the compiler error occurs in every single source file that uses TBB and I don't think I changed anything since my last successful compilation (besides updating VS).
One possibility that comes to my mind is related to this question. If msvc somehow inherits the base class constructors by default, a default constructor would be inherited explaining the error. But testing this scenario seems to disprove it (as the code compiles).
Why is msvc complaining here?
Update
This minimal example reproduces the error on my system:
#include <vector>
#include <tbb/tbb.h>
#include <tbb/flow_graph.h>
void main()
{
std::vector<int> src{1, 2, 3, 4, 5};
tbb::parallel_for_each(src.begin(), src.end(), [](int) { });
}
Update 2
Looks like just including tbb/tbb.h causes the error to occur. I don't even need to call anything. Rebuilding tbb with the new compiler version didn't help either.
Edit
Cross issue on github.

Simply removing /permissive- (e.g. set Comformance Mode to No in the C/C++ options) gets past this issue. I presume Intel will fix this soon.

This is a compiler bug when /permissive- option is used. It can be reproduced with the following code:
struct U {
template<typename T>
void foo() {
class A {
int& iref;
public:
A(int& ir) : iref(ir) { }
};
int the_answer = 42;
A a(the_answer);
}
};
int main() {
U u;
u.foo<int>();
return 0;
}
The code is perfectly valid, compliant C++. As you can see, the reference is explicitly initialized in the member initializer list of the constructor. Also this is seemingly a regression in VS, because at least the initial release of VS 2017 (15.0.something) compiles this code with /permissive-.

Related

Function with default argument doesn't compile with VC++, but does with g++ and clang

I've searched this site and cannot find a solution to my problem. I have reduced my sample code down as much as I think I can while still retaining the relevant error. I am left with the following two files:
test.hpp
namespace models {
template<typename FloatingPoint>
class ellipsoid {
public:
explicit ellipsoid(FloatingPoint = 6378137.0);
private:
FloatingPoint a_;
};
template<typename FloatingPoint>
ellipsoid<FloatingPoint>::ellipsoid(FloatingPoint a) : a_(a) {}
} // End namespace models
// Function declaration
template<typename FloatingPoint>
FloatingPoint compute(FloatingPoint,
const models::ellipsoid<FloatingPoint>& =
models::ellipsoid<FloatingPoint>());
// Function definition
template<typename FloatingPoint>
FloatingPoint compute(FloatingPoint x,
const models::ellipsoid<FloatingPoint>& model) {
return 3.14;
}
test.cpp
#include "test.hpp"
int main() {
compute(10.0);
return 0;
}
When I compile the above code using VC++ 2017, I get the following error:
error C2512: 'models::ellipsoid<FloatingPoint>': no appropriate default constructor available
note: No constructor could take the source type, or constructor overload resolution was ambiguous
Both clang and g++ compile this without a problem. Also, if I remove the ellipsoid class from the namespace models, and remove the models:: invocations in the compute function, it then compiles fine using VC++. Is this a bug within the VC++ compiler, or have I got a bug in my code?
This was a bug in VC++, which was fixed in Visual Studio 2019 since compiler version 19.23. Demo: https://gcc.godbolt.org/z/a5TxPa8ac

cds library: michael_deque causes crash when pushing back derived type of custom type (only in release mode)

I'm using VS2012 with default optimization settings (/O2), and this problem exists only in release mode.
I have some code that uses a michael_deque (with the standard GC) and a pointer to (abstract) type T.
When I try to push back a pointer to a type that is derived from T, the application crashes while exiting the push_back() function of michael_deque.
The problem seems to depend precisely on this specific type T, because writing a dummy class foo, deriving from it in class bar (and printing something in the constructor to avoid it being optimized away) and then pushing back new bar() to michael_deque does not cause a crash.
The classT in question is this:
class Task
{
public:
Task() : started(false), unfinishedTasks(1), taskID(++taskIDCounter) {};
Task(unsigned int parentID_) : started(false), unfinishedTasks(1), taskID(++taskIDCounter), parentID(parentID_)/*, taken(0)*/ {};
virtual ~Task() = 0 {};
virtual void execute() final
{
this->doActualWork();
unfinishedTasks--;
}
virtual void doActualWork() = 0;
public:
unsigned int taskID; //ID of this task
unsigned int parentID; //ID of the parent of this task
bool started;
std::atomic<unsigned int> unfinishedTasks; //Number of child tasks that are still unfinished
std::vector<unsigned int> dependencies; //list of IDs of all tasks that this task depends on
};
The error can be reproduced in a minimal program (if you happen to have an environment that can execute this in the same manner as I do, just put an std::atomic<unsigned int> taskIDCounter somewhere where the Task class can see it) :
#include <cds/container/michael_deque.h>
#include "task.hpp"
class a : public Task
{
a()
{
std::cout<<"dummy print"<<std::endl;
}
virtual ~a()
{
}
virtual void doActualWork()
{
std::cout<<"whatever"<<std::endl;
}
};
int main()
{
cds::Initialize();
{
cds::gc::HP hpGC;
cds::gc::HP::thread_gc myThreadGC;
cds::container::MichaelDeque<cds::gc::HP,Task*> tasks;
tasks.push_back(new a()); //will crash at the end of push_back
}
cds::Terminate();
}
What could be the cause of this? Do I do something undefined in the class Task which causes problems in the optimization problems?
It was indeed a compiler bug. More specifically, it was a bug associated with Visual Studio 2012's atomic implementation.
Some template specializations of the std::atomic class modify the stack frame pointer (ebp) without backing it up on and popping it form the stack before/after the modification. The libcds library uses one of these specializations, and the resulting incorrect frame pointer sometimes causes illegal memory access (the undefined behavior seems to prevent catastrophic failure in debug mode) when running outside the scope of a function.
The fix in this special case was to make libcds use a different atomics library then the standard one provided by Visual Studio. The library decides which implementation to use in cxx11_atomic.h:
#if defined(CDS_USE_BOOST_ATOMIC)
# error "Boost.atomic is not supported"
//# include <boost/version.hpp>
//# if BOOST_VERSION >= 105300
//# include <boost/atomic.hpp>
//# define CDS_ATOMIC boost
//# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
//# define CDS_CXX11_ATOMIC_END_NAMESPACE }
//# else
//# error "Boost version 1.53 or above is needed for boost.atomic"
//# endif
#elif CDS_CXX11_ATOMIC_SUPPORT == 1
// Compiler supports C++11 atomic (conditionally defined in cds/details/defs.h)
# include <cds/compiler/cxx11_atomic_prepatches.h>
# include <atomic>
# define CDS_ATOMIC std
# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
# define CDS_CXX11_ATOMIC_END_NAMESPACE }
# include <cds/compiler/cxx11_atomic_patches.h>
#else
# include <cds/compiler/cxx11_atomic.h>
# define CDS_ATOMIC cds::cxx11_atomics
# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomics {
# define CDS_CXX11_ATOMIC_END_NAMESPACE }}
#endif
The second branch of the if statement can be changed to something like
#elif CDS_CXX11_ATOMIC_SUPPORT == 255
which will cause the library to use its own atomics implementation at all times.

Effective C++ Item 43 Know how to access names in templatized base classes

In Item 43 of the book, it is said that the code below will not compile.
My understanding is that, compilation error occurs when the method LoggingMsgSender::sendClearMsg is instaniated.
However, for the three compilers (VC 2005, gcc 4.4.1, and one for embeded device) I have tried.
None of them show any compilation error.
Are there any compiler which can show the error as mentioned in the book?
Any suggestions are welcome.
Thank you for your help.
(I have found a potential compiler bug in VC 2005 in my source related to this kind
of template base-class function call, that's why I want to the compilation error.
That's a long story...)
class CompanyX
{
public:
void sendClearText(){};
};
typedef int MsgInfo;
template<typename Company>
class MsgSender {
public:
void sendClear(const MsgInfo&)
{
Company c;
c.sendClearText();
}
};
template<typename Company>
class LoggingMsgSender : public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info)
{
sendClear( info ); // ERROR : will not compile despite clearly being in base class.
}
};
int main()
{
LoggingMsgSender<CompanyX> sender;
sender.sendClearMsg(1); // specialization of the method!!!
}
http://liveworkspace.org/code/273c71cd53111dd8c6aaa54e64c53548 for example. get an error. in this case in function sendClearMsg we should use this->sendClear(info); compiler is gcc 4.7.1. And so, now is 2012 year, why you use old compilers?

Visual Studio 2010 compile error with std::string?

So this is possibly the strangest thing I've seen recently and was curious how this could happen. The compiler gave me an error saying that std::string is undefined when used as a return type but not when used as a parameter in methods of a class!
#pragma once
#include <string>
#include <vector>
// forward declarations
class CLocalReference;
class CResultSetHandle;
class MyClass
{
public:
MyClass() {}
~MyClass {}
void Retrieve(const CLocalReference& id, CResultSetHandle& rsh, std::string& item); // this is fine
const std::string Retrieve(const CLocalReference& id, CResultSetHandle& rsh); // this fails with std::string is undefined?!?!
};
Doing a Rebuild All it still happened I had to choose clean solution and then Rebuild All again after for the universe to realign. While it's resolved for the moment I'd still like to know what could have caused this because I'm at a loss as to why when there should be no conflicts especially when I always use fully qualified names for STL.
This is probably a compiler bug. I have seen several others in VS2010.

Error C2275 caused by template member function. Is this code wrong?

I think I've run into a (possible) VC6 (I know. It's what we use.) compiler error, but am open to the fact that I've just missed something dumb. Given the following code (It's just an example!):
#include <iostream>
// Class with template member function:
class SomeClass
{
public:
SomeClass() {};
template<class T>
T getItem()
{
return T();
};
};
// Dummy just used to recreate compiler error
class OtherClass
{
public:
OtherClass() {};
};
std::ostream& operator<<( std::ostream& oStr, const OtherClass& obj )
{
return oStr << "OtherClass!";
};
// Main illustrates the error:
int main(int argc, char* argv[])
{
SomeClass a;
OtherClass inst2 = a.getItem<OtherClass>(); // Error C2275 happens here!
std::cout << inst2 << std::endl;
return 0;
}
If I try to compile this code VC6, dies on a.getItem<OtherClass>() yielding:
Error C2275: 'OtherClass' : illegal use of this type as an expression.
Have I overlooked some trivial syntax issue? Am I breaking a rule?
This code compiles just fine under gcc 4.3.4. Is it yet another compliance issue with VC6?
Thanks!
Among many other things with the word template in it, VC6 couldn't deal with function templates where the template parameters aren't also function parameters. The common workaround was to add a dummy function parameter:
template<class T>
T getItem(T* /*dummy*/ = NULL)
{
return T();
} // note: no ; after function definitions
However, in general, VC6 is pretty lame and often chokes as soon as a TU contains the template keyword. I had to beat my head against it for several years (big code base compiled with several compilers/compiler versions; VC6 giving us an endless amount of trouble) and was very glad when I got rid of it in 2003.
This is likely to be a VC6 issue. Although VC6 compiles most basic templates correctly it is known to have many issues when you start to move towards the more advanced template uses. Member templates are an area where VC6 is known to be weak on conformance.
I believe that's another bug in VC6, you should really switch to a more up-to-date compiler.