Community
cancel
Showing results for 
Search instead for 
Did you mean: 
jimdempseyatthecove
Black Belt
145 Views

NULL promoted to class

Jump to solution
I was performing a major re-write of some code and ran into one of those situations where looking at the code did not did not convey anything was wrong with it.

The former code had a class that contained pointers to some objects, and the ctor of that class nulled out the pointers.

fee = NULL;
fi = NULL;
fo = NULL;

Where NULL is promoted to pointer of any type.

In the rewrite of the code the pointers were replaced with the class objects using same names in the code.
However, a programming error on my part, I left the former pointer NULL-ing code in the ctor.

The compiler did not produce an error, I do not know if it should or should not, but the result was:

The compiler promoted the NULL to the class object,
peformed a default copy operator,
then destroyed the NULL class object.

Is this a feature or bug???

Jim Dempsey
0 Kudos
1 Solution
Judith_W_Intel
Employee
145 Views


If you declare a constructor "explicit" it can only be used for construction of an object, not for conversions.

Explanation here:

http://www.glenmccl.com/tip_023.htm

Is that what you want?

Judy

View solution in original post

24 Replies
Judith_W_Intel
Employee
129 Views

If you can show us a small test case that would help. NULL is usuallya macro for (void *)0 which can be converted to any pointer type. You should not be able to assign NULL to a class object unless there is anon explicitconstructorwith a pointer type argument or an appropriateconversion operator.Using the C++11new nullptr and nullptr_t typeis generally safer.

If the reference compiler (Gnu or Microsoft) doesn't give an error/warning then we cannot give oneeither. But it would be possible to add a remark if we can detect code that will likely lead to bad runtime behaviour.

Judy
jimdempseyatthecove
Black Belt
129 Views
I will see if I can make a simple reproducer (next year).

>>If the reference compiler (Gnu or Microsoft) doesn't give an error/warning then we cannot give oneeither.

Not so. you cannot get off that easy. If the code is wrong, you give the error.

The same argument above by you (Intel) can apply to the others as well.

Jim
JenniferJ
Moderator
129 Views
The compiler promoted the NULL to the class object,
peformed a default copy operator,
then destroyed the NULL class object.


could you give more detail on the above? does your class have an overloaded operator to take "NULL" and convert to the class object? I could not duplicate it with a small test case:

cmd: icl /Od /EHsc t.cpp

[bash]#include 
using namespace std;

class B
{
public:
	B():b(10) {
	cout << "in B()" << endl;
	};
	~B() {
	cout << "in ~B()" << endl;
	};
private:
	int b;
};

class A
{
public: 
	A() { 
		p1 = NULL;
		cout << "in A(); P1= NULL" << endl;
	};
	~A(){
		if (p1 != NULL)
			delete p1;
		cout << "in ~A()" << endl;
	};
	void SetVars() {
		if (p1 == NULL)
		{
			cout << "in SetVars(): p1 = new B(); " << endl;
			p1 = new B();
		}
	}
private:
	B* p1;
};

int main(int argc, char *argv[])
{
  cout << "start" << endl;
  A *t1 = new A;
  cout << "allocated A object" << endl;
  t1->SetVars();
  delete t1;
  cout << "deleted A object" << endl;

  return 0;
}












[/bash]
jimdempseyatthecove
Black Belt
129 Views
  1. {
  2. coutlt;lt;"start"lt;lt;endl;
  3. AanA;
  4. coutlt;lt;"instantiatedan Aobject"lt;lt;endl;
  5. anA = NULL;
  6. coutlt;lt;"NULL'ed an Aobject"lt;lt;endl;
  7. return0;
  8. }

    I am not on my system, try the above. Your code did not assign NULL to an object.

    Jim
JenniferJ
Moderator
129 Views

with this change, I got a compiler error:

C:>icl /Od /EHsc t.cpp

Intel C++ Compiler XE for applications running on IA-32, Version 12.1.1.258 Build 20111011

Copyright (C) 1985-2011 Intel Corporation. All rights reserved.

t.cpp

t.cpp(45): error: no suitable constructor exists to convert from "int" to "A"

t1 = NULL;

^

compilation aborted for t.cpp (code 2)


So icl did report an error for this simple case. is it the same for you with this testcase?

Jennifer
jimdempseyatthecove
Black Belt
129 Views
Your code produces the expected error (nosuitableconstructor operator).
My code did not.

I will see if I can make a simple reproducer.

A difference in my situation is that I used a class with a base class. The base class (I seem to recall) was the one getting ctor/dtor'd.

Jim
jimdempseyatthecove
Black Belt
129 Views
As a quick test, change your

class A {

to

class A : B {

and see what happens.

Jim
JenniferJ
Moderator
129 Views
Still get the compilation error.

t.cpp(45): error: no operator "=" matches these operands

operand types are: A = int

t1 = NULL;

^

also attached the file t.cpp.

Jennifer
SergeyKostrov
Valued Contributor II
129 Views
...
Is this a feature or bug???
...


Jim,could youprovide areal Test-Case that reproduces the problem?

I've created a very simple Test-Case and I was able to assign NULL to a class-based variable if I declare a
C++ operator '=' ( see Test-Case 3 ). The Test-Case is verified with four different C/C++ compilers.

My conclusion is as follows:

If a C/C++ compiler allows NULL assignment to some class-based automaticvariable, declared on the stack
or as global\staticand operator=( int ) is not declared, this is possiblya compiler'sbug.

...
class CTestA
{
public:
CTestA(){};
virtual ~CTestA(){};

// Test-Case 1
CTestA & operator=( CTestA &ta ){ return ( CTestA & )*this; };

// Test-Case 2
// CTestA & operator=( int &ia ){ return ( CTestA & )*this; };

// Test-Case 3
CTestA & operator=( int ia ){ return ( CTestA & )*this; };
};

class CTestB : public CTestA
{
public:
CTestB(){};
virtual ~CTestB(){};

// Test-Case 1
CTestB & operator=( CTestB &tb ){ return ( CTestB & )*this; };

// Test-Case 2
// CTestB & operator=( int &ib ){ return ( CTestB & )*this; };

// Test-Case 3
CTestB & operator=( int ib ){ return ( CTestB & )*this; };
};

class CTestC : CTestA
{
public:
CTestC(){};
virtual ~CTestC(){};

// Test-Case 1
CTestC & operator=( CTestC &tc ){ return ( CTestC & )*this; };

// Test-Case 2
// CTestC & operator=( int &ic ){ return ( CTestC & )*this; };

// Test-Case 3
CTestC & operator=( int ic ){ return ( CTestC & )*this; };
};
...

void main( void )
{
// MS C/C++ ( VS 2005 ) - Compiled
// Borland C++ v5.5.1 - Compiled
// MinGW v3.4.2- Compiled
// Turbo C++ v3.0.0 - Compiled if only one 'operator=( int ... )' is declared
// Failed if both operator=( int & ) and operator=( int ) are declared
// Error: 'CTestX::operator =(int)' cannot be distinguished from 'CTestX::operator =(int &)'

CTestA ta;
ta = NULL;
ta = ( int )NULL;
ta = ( int )0;
ta = ( int )0xFFFFFFFF;

CTestB tb;
tb = NULL;
tb = ( int )NULL;
tb = ( int )0;
tb = ( int )0xFFFFFFFF;

CTestC tc;
tc = NULL;
tc = ( int )NULL;
tc = ( int )0;
tc = ( int )0xFFFFFFFF;
}

jimdempseyatthecove
Black Belt
129 Views
Attached is a test case:

Place break in Foos::showBug() at statement

input = NULL;

Then run and use Step Into

Jim
jimdempseyatthecove
Black Belt
129 Views
Bug shows with w_ccompxe_2011.7.258

Jim Dempsey
JenniferJ
Moderator
129 Views
Hi Jim,
There is a new bug introduced today that prevented the attachment being uploaded. so I could not see your testcase.

could you paste the code to the response instead?

thanks,
Jennifer
jimdempseyatthecove
Black Belt
129 Views
Jennifer,

Hope this works.

[cpp]// NULLtoClass.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include 

// ** Intel **
// The following are typedefs, defines, class, struct, etc...
// for missing headers in this shortened example program

typedef __int64 Interlocked_t;	// QuickThread.h
typedef short qtPlacement;	// QuickThread.h
struct qtControl { int	someStuff; void WaitTillDone() { return; } };	// QuickThread.h

namespace qt
{

struct parallel_manifold_token
{
	// member variables:
	void*	Context;			// User context
	void*	This;				// pointer to the data flow object
								// or
								// pointer to the resource flow object
	// member functions:
	// ctor
	parallel_manifold_token();
	// dtor
	~parallel_manifold_token();
};

struct parallel_manifold_context
{
	// member variables:
	void*						Context;		// User context
	Interlocked_t				maxTokens;		// maximum number of tokens permitted
	volatile Interlocked_t		nTokens;		// number of tokens currently in system
	parallel_manifold_token*	token_table;	// table of tokens
	
	// member functions:
	// ctor
	parallel_manifold_context();
	// dtor
	~parallel_manifold_context();
	// init function
	// sets User Context, maxTokens, allocates empty token_table[maxTokens]
	void init(void*	_Context, Interlocked_t _maxTokens);

	parallel_manifold_context(void*	_Context, Interlocked_t _maxTokens)
	{ init(_Context, _maxTokens); }

	void addToken(int i, void*	_Context, void* node);

	// retire token via address of some token in token_table
	// user code pass parallel_manifold_token*
	void retireToken(parallel_manifold_token* token);
	void WaitTillDone();
};

struct token_proxy
{
	Interlocked_t x;	// magic number referencing token in parallel_manifold_context
};

struct parallel_resource_manifold;

struct parallel_manifold_base
{
public:
	// member variables:
	parallel_manifold_context*	context;
	parallel_manifold_token*	token_table;	// local copy of context->token_table
	Interlocked_t				ringBufferSize;
	token_proxy*				ringBuffer;
	volatile Interlocked_t		fillIndexABA;
	volatile Interlocked_t		emptyIndexABA;
	int							nServerThreads;
	qtPlacement					Placement;
	void (*server_f)(parallel_manifold_token*);
	parallel_resource_manifold*	resource;
	qtControl					control;
	bool						take_stats;
	__int64						nFills;			// updated when take_stats == true
	__int64						nTaskEnqueues;	// updated when take_stats == true

	// member functions:
	// ctor
	parallel_manifold_base();
	// dtor
	~parallel_manifold_base();
	// initializer
	void init( parallel_manifold_context* _context, parallel_resource_manifold*	_resource = NULL);
	// ctor with args
	parallel_manifold_base( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{
		init(_context,_resource);
	}
	void WaitTillDone() { control.WaitTillDone(); }
	static void fillShellStatic(parallel_manifold_base*);
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 0);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
}; // parallel_manifold_base

// Ring buffers are Ordered or FIFO
// Ordered:
//	Tokens may arrive in any order
//	Tokens are dispatched to the action task in circular sequence order
//	0, 1, 2, ..., n, 0, 1, 2, ..., n, 0, 1, 2, ..., n, ...
//
// FIFO:
//	Tokens may arrive in any order
//	Tokens are dispatched in arrival sequence order

// Single-Producer, Single-Consumer Ordered ring buffer
struct parallel_manifold_SPSC_Ordered : parallel_manifold_base
{
	parallel_manifold_SPSC_Ordered();
	parallel_manifold_SPSC_Ordered( parallel_manifold_context* _context );
	parallel_manifold_SPSC_Ordered( parallel_manifold_context* _context, parallel_resource_manifold* _resource );
	~parallel_manifold_SPSC_Ordered();
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 1);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};

// Single-Producer, Single-Consumer FIFO
struct parallel_manifold_SPSC_FIFO : parallel_manifold_base
{
	parallel_manifold_SPSC_FIFO() {;}
	parallel_manifold_SPSC_FIFO( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{ init(_context,_resource); }
	~parallel_manifold_SPSC_FIFO() {;}
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 1);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};

// Multi-Producer, Single-Consumer Ordered
struct parallel_manifold_MPSC_Ordered : parallel_manifold_base
{
	parallel_manifold_MPSC_Ordered() {;}
	parallel_manifold_MPSC_Ordered( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{ init(_context,_resource); }
	~parallel_manifold_MPSC_Ordered() {;}
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 1);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};

// Multi-Producer, Single-Consumer FIFO
struct parallel_manifold_MPSC_FIFO : parallel_manifold_base
{
	parallel_manifold_MPSC_FIFO() {;}
	parallel_manifold_MPSC_FIFO( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{ init(_context,_resource); }
	~parallel_manifold_MPSC_FIFO() {;}
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 1);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};

// Single-Producer, Multi-Consumer, FIFO
struct parallel_manifold_SPMC_FIFO : parallel_manifold_base
{
	parallel_manifold_SPMC_FIFO() {;}
	parallel_manifold_SPMC_FIFO( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{ init(_context,_resource); }
	~parallel_manifold_SPMC_FIFO() {;}
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 0);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};

// Multi-Producer, Multi-Consumer, FIFO
struct parallel_manifold_MPMC_FIFO : parallel_manifold_base
{
	parallel_manifold_MPMC_FIFO() {;}
	parallel_manifold_MPMC_FIFO( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{ init(_context,_resource); }
	~parallel_manifold_MPMC_FIFO() {;}
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 0);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};

#if 0
struct x : parallel_manifold_base
{
	x() {;}
	x( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )
	{ init(_context,_resource); }
	~x() {;}
	virtual void run(
		qtPlacement					_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 0);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
};
#endif

struct parallel_manifold_functor_token_list
{
	void (*server_f)(parallel_manifold_functor_token_list*);
	intptr_t	nTokens;
	parallel_manifold_token*	token_list[];
};

parallel_manifold_functor_token_list*
parallel_manifold_functor_token_list_new(
		void (*_server_f)(parallel_manifold_functor_token_list*),
		size_t _nTokens);

void parallel_manifold_functor_token_list_delete(parallel_manifold_functor_token_list* p);

struct resource_token_proxy : token_proxy
{
	parallel_manifold_base*	pmb;
};

struct parallel_resource_manifold
{
	// member variables:
	parallel_manifold_context*			context;
	parallel_manifold_token*			token_table;	// local copy of context->token_table
	Interlocked_t						ringBufferSize;
	resource_token_proxy*				ringBuffer;
	volatile Interlocked_t				fillIndexABA;
	volatile Interlocked_t				emptyIndexABA;
	bool								take_stats;
	__int64								nFills;			// updated when take_stats == true
	__int64								nTaskEnqueues;	// updated when take_stats == true
	parallel_resource_manifold();
	~parallel_resource_manifold();
	// init function
	void init(parallel_manifold_context* _context);
	virtual void fillShell();
	virtual void fill(parallel_manifold_token* t);
	virtual void fill(parallel_manifold_token* t, size_t order);
	virtual parallel_manifold_token* empty();
	parallel_manifold_token* empty(parallel_manifold_base* pmb);
}; // struct parallel_resource_manifold

struct parallel_multi_port_manifold_port
{
	parallel_manifold_context*	context;
	parallel_manifold_token*	token_table;	// local copy of context->token_table
	Interlocked_t				ringBufferSize;
};

struct parallel_multi_port_manifold_base
{

	parallel_manifold_context*	context;
	parallel_manifold_token*	token_table;	// local copy of context->token_table
	Interlocked_t				ringBufferSize;
	token_proxy*				ringBuffer;
	volatile Interlocked_t		fillIndexABA;
	volatile Interlocked_t		emptyIndexABA;
	int							nServerThreads;
	qtPlacement					Placement;
	void (*server_f)(parallel_manifold_token*);
	qtControl					control;

	bool						take_stats;
	__int64						nFills;			// take_stats
	__int64						nTaskEnqueues;	// take_stats

	parallel_multi_port_manifold_base();
	~parallel_multi_port_manifold_base();
	

	void init(
		parallel_manifold_context*	_context,
		qtPlacement	_Placement,
		void (*_server_f)(parallel_manifold_token*),
		int	_maxThreads = 0);
	
}; // struct parallel_multi_port_manifold_base

struct parallel_multi_port_manifold : parallel_multi_port_manifold_base
{ void*	vp; };

parallel_manifold_base::parallel_manifold_base()
{ return; }

parallel_manifold_base::~parallel_manifold_base()
{ return; }

void parallel_manifold_base::init(parallel_manifold_context * ctx, parallel_resource_manifold * mn)
{ return; }


void parallel_manifold_base::run(qtPlacement, void (__cdecl*fn)(struct qt::parallel_manifold_token *), int n)
{ return; }

void parallel_manifold_base::fillShell()
{ return; }


void parallel_manifold_base::fill(parallel_manifold_token * t, unsigned int n)
{ return; }

void parallel_manifold_base::fill(parallel_manifold_token *t)
{ return; }

parallel_manifold_token * parallel_manifold_base::empty()
{ return NULL; }

void parallel_manifold_SPSC_FIFO::run(qtPlacement, void (*fn)(parallel_manifold_token *), int n)
{ return; }
	
void parallel_manifold_SPSC_FIFO::fillShell()
{ return; }
	
void __thiscall qt::parallel_manifold_SPSC_FIFO::fill(parallel_manifold_token * t, unsigned int n)
{ return; }
	
void __thiscall qt::parallel_manifold_SPSC_FIFO::fill(parallel_manifold_token * t)
{ return; }

parallel_manifold_token *parallel_manifold_SPSC_FIFO::empty()
{ return NULL; }

} // namespace qt

using namespace std;
using namespace qt;

class FooManager {
	void*	stuff;
};

class Foos {
public:
	Foos(int ep, FooManager* fm);
	virtual ~Foos();

	void StartFooProcessing();
	void StopFoo();
	void writeBuffer(parallel_manifold_token* token);
	void showBug();
protected:
	// Use this for L7 Foo
	void SetupFoo(int ep);
	void FooProcess();

private:
	int 				endpoint;
	int 				numberToken;

public:
	FooManager* 		flowMgr;
	volatile int simulateNewPacket;
	// flow diagram:
//								(initialization)
//									  |
//									  |________
//									  V		      (top)
	parallel_manifold_SPSC_FIFO	input;//		|
//									  |-------->|
//									  V			|
	parallel_manifold_SPSC_FIFO	process;//		|
//									  ||------->|
//									  VV		|
	parallel_manifold_SPSC_FIFO	output;//		|
};

Foos::Foos(int n,class FooManager *fm)
{
	return;
}

Foos::~Foos()
{
	return;
}

void Foos::showBug()
{
	input = NULL;
}
int _tmain(int argc, _TCHAR* argv[])
{
	FooManager* flowMgr = new FooManager;
	Foos* flow = new Foos(0,flowMgr);
	flow->showBug();
	return 0;
}

[/cpp]
Jim Dempsey
JenniferJ
Moderator
129 Views
Yes, it helps.

It's because your class parallel_manifold_SPSC_FIFO has a constructor:

parallel_manifold_SPSC_FIFO( parallel_manifold_context* _context, parallel_resource_manifold* _resource = NULL )


so it can create an object from NULL. it does not like a bug to me.

Let me attach the simpler test here t.cpp.

Jennifer

jimdempseyatthecove
Black Belt
129 Views
That is aconstructor with two arguments. One required, one optional.

The required argument is (was) missing in the

input = NULL;

and there is no operator=()

both of which should have been rquired.

What this appears to have done is cast

(void*)0

into

(parallel_manifold_context*)0

a) Then assume an implied conversion operator. Or
b) implied ctor with argument of the point.

Actually I think in this case it would be better called a dereferencing copy operator.

There is no conversion operator (for a), and the syntax is not right to instigate a ctor.

An additional curiosity is the dtor is also run immediately after the assignment, therefore indicating the statement is performing an operator=() using a temporary object created from a (missing) conversion operator(parallel_manifold_SPSC_FIFO)(parallel_manifold_context*), also not specified.

To me, this seems like a bug.

Jim Dempsey
JenniferJ
Moderator
129 Views
no, what the compiler did is : creating an object from "NULL" using ctor "MyClass(A* a, B* b=NULL)".

The strange thing is if I add the "A& operator=(A& in){}", both icl & cl emits an error below instead:

t.cpp(47): error: no operator "=" matches these operands

operand types are: B = int

bobj = NULL; // should error here

^


Jennifer
SergeyKostrov
Valued Contributor II
129 Views
...
To me, this seems like a bug.
...
Jim Dempsey


Hello everybody,

I've just completedCompilations with 4 different C/C++ compilers. I'll do Runtime verifications( debugging ) tomorrow.

So, even a Turbo C++ v3.0.0 compiled the Test-Casewith somemodifications. Here is its output:

Turbo C++ Version 3.00 Copyright (c) 1992 Borland International
tcctes~1.cpp:
Turbo Link Version 5.0 Copyright (c) 1992 Borland International
Error: Undefined symbol parallel_manifold_base::run(short,void(far*)(parallel_manifold_token near*),int) in module tcctes~1.cpp
Available memory 3402856
TccTestApp -1 error(s), 0 warning(s)

Note: Please don't pay attention for a linking error. This is a different "story".

SUMMARY:

// MS C/C++ ( VS 2005 ) - Compiled \ Modifications - 0 \ One Warning

struct parallel_manifold_functor_token_list
{
...
parallel_manifold_token* token_list[];
// Warning C4200: nonstandard extension used : zero-sized array in struct/union
// Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
};

// Borland C++ v5.5.1 - Compiled \ Modifications - 3 \ No Warnings
//Doesn't support:
'intptr_t'
'__thiscall'

...
struct parallel_manifold_functor_token_list
{
void (*server_f)(parallel_manifold_functor_token_list*);
// intptr_t nTokens;
int nTokens;
parallel_manifold_token* token_list[];
};
...
void /*__thiscall*/ qt::parallel_manifold_SPSC_FIFO::fill(parallel_manifold_token * t, unsigned int n)
{ return; }

void /*__thiscall*/ qt::parallel_manifold_SPSC_FIFO::fill(parallel_manifold_token * t)
{ return; }
...

// MinGW v3.4.2 - Compiled \ Modifications - 2 \ No Warnings
//Doesn't support
'__thiscall'

...
void /*__thiscall*/ qt::parallel_manifold_SPSC_FIFO::fill(parallel_manifold_token * t, unsigned int n)
{ return; }

void /*__thiscall*/ qt::parallel_manifold_SPSC_FIFO::fill(parallel_manifold_token * t)
{ return; }
...

// Turbo C++ v3.0.0 - Compiled \ Modifications ->10\ No Warnings
//Doesn't support:
'iostream'
'__int64'
'namespace qt'
'qt::parallel_manifold_token'
'using namespace qt'
'using namespace std'
'bool'
'__thiscall'
'void parallel_manifold_functor_token_list_delete(parallel_manifold_functor_token_list* p)' commented
'void parallel_manifold_base::run(qtPlacement, void (__cdecl*fn)(struct /*qt::*/parallel_manifold_token *), int n)' commented ( creates a linking error )

Judith_W_Intel
Employee
129 Views
>> That is aconstructor with two arguments. One required, one optional.

Correct. The trailing (second argument) is defaulted.

>> The required argument is (was) missing in the

>> input = NULL;

No. NULL is used for the required (first) argument and the default argument valueis used for the second.

>> and there is no operator=()

Every class has an implicit assignment operator generated by the compilerif the user does not declare one explicitly.


JenniferJ
Moderator
129 Views

Hope you have read Judy's explaination.

Also I checked with our compiler FE experts,and below is my understanding when compiler see "input = NULL;"
1. "NULL" is a valid value for any pointer variable (as an init value).
2. compiler created a tempoary object with "NULL" based on ctor A(B*p, C*p2=NULL) ---- the 2nd parameter is optional.
3. compiler uses the "default assignment operator" generated by the compiler itself to assign the temp object to variable "input" when there is no assignment operator overloading.
4. in my testcase the overloading assignement operator is "B& operator (B& in)", but it should be "B& operator (B const & in)" instead. if changing to the later one, the compiler will not issue the error.

One rule worth note here from our compiler expert and this explains why "B& operator (B const & in)" is needed:

C++ overload resolution has a special rule: a reference-to-non-const parameter is not allowed to bind to a temporary object.


Jennifer
SergeyKostrov
Valued Contributor II
20 Views
>>...
>>To me, this seems like a bug.
>>...
>>Jim Dempsey

I don't see any problems with C/C++ compilers I tested. I would rather change how 'input' member is
initialized. Here is an example:

...
void Foos::showBug()
{
// input = NULL;
input.init( NULL );
// input.init( NULL, NULL );
}
...

When you try to assign NULL to 'input' member two default C++ operators '='are called:

...
qt::parallel_manifold_SPSC_FIFO::operator=
...
004B8A5A call qt::parallel_manifold_base::operator= (4A55CDh)
...
004B8A75 ret 4
...

Here is a screenshot:

Here is a summary\outputs of my tests:

// Test-Case 1: Output without a C++ operator=( int ) in a parallel_manifold_SPSC_FIFO class

new FooManager
new Foos( 0, flowMgr )
Foos::Foos(int n,class FooManager *fm)
Foos::showBug()
input = NULL
parallel_manifold_SPSC_FIFO::parallel_manifold_SPSC_FIFO( ... )
parallel_manifold_base::init( ... )
delete flow
Foos::~Foos()
delete flowMgr

// Test-Case 2: Output if a C++ operator=( int ) added in a parallel_manifold_SPSC_FIFO class

new Foos( 0, flowMgr )
Foos::Foos(int n,class FooManager *fm)
Foos::showBug()
input = NULL
delete flow
Foos::~Foos()
delete flowMgr

...
struct parallel_manifold_SPSC_FIFO : parallel_manifold_base
{
...
parallel_manifold_SPSC_FIFO & operator=( int )
{
return ( parallel_manifold_SPSC_FIFO & )*this;
};
...
};
...

// Test-Case 3: Output if a call to input.init( ... ) added instead of input = NULL assignment

// Without a C++ operator=( int ) // With a C++ operator=( int )

new FooManager new FooManager
new Foos( 0, flowMgr ) new Foos( 0, flowMgr )
Foos::Foos(int n,class FooManager *fm)Foos::Foos(int n,class FooManager *fm)
Foos::showBug() Foos::showBug()
parallel_manifold_base::init( ... ) parallel_manifold_base::init( ... )
delete flow delete flow
Foos::~Foos() Foos::~Foos()
delete flowMgr delete flowMgr

They are identical and this is right.

...
void Foos::showBug()
{
CrtPrintf( RTU("Foos::showBug()\n") );
// CrtPrintf( RTU("input = NULL\n") );
// input = NULL;
input.init( NULL );
// input.init( NULL, NULL );
}
...

// Disassembler Codes - for Test-Case 1

...
qt::parallel_manifold_SPSC_FIFO::operator=
004B8A30 push ebp
004B8A31 mov ebp,esp
004B8A33 sub esp,0CCh
004B8A39 push ebx
004B8A3A push esi
004B8A3B push edi
004B8A3C push ecx
004B8A3D lea edi,[ebp-0CCh]
004B8A43 mov ecx,33h
004B8A48 mov eax,0CCCCCCCCh
004B8A4D rep stos dword ptr es:[edi]
004B8A4F pop ecx
004B8A50 mov dword ptr [ebp-8],ecx
004B8A53 mov eax,dword ptr [__that]
004B8A56 push eax
004B8A57 mov ecx,dword ptr [this]
004B8A5A call qt::parallel_manifold_base::operator= (4A55CDh)
004B8A5F mov eax,dword ptr [this]
004B8A62 pop edi
004B8A63 pop esi
004B8A64 pop ebx
004B8A65 add esp,0CCh
004B8A6B cmp ebp,esp
004B8A6D call @ILT+36765(__RTC_CheckEsp) (4ADFA2h)
004B8A72 mov esp,ebp
004B8A74 pop ebp
004B8A75 ret 4
...

Reply