vector of pimpl's / weird behavior

E

er

hi,

the code below generates the following behavior. cld someone please
help understand it?
1) clean project + build project generates build errors (see bottom)
2) build a second time, errors disappears, run: ok
3) uncomment [1] and comment [2], no problem
4) uncomment [3] and [4], also no problem

#ifndef A_IMPL_H_
#define A_IMPL_H_
#include <memory>
class A_impl{
public:
A_impl();
virtual ~A_impl(){};
virtual std::auto_ptr<A_impl> clone()const=0;
private:
A_impl& operator=(const A_impl&);
};
#endif /*A_IMPL_H_*/

#ifndef A_H_
#define A_H_
#include <memory>
//#include "A_impl.h" // [1]
class A_impl;//[2]
class A{
public:
A(const A_impl& impl_);
A(const A& o);
A& operator=(const A& rhs);
private:
A();
std::auto_ptr<A_impl> pimpl;
};
#endif /*A_H_*/

#ifndef AS_H_
#define AS_H_
#include <vector>
#include "A.h"
class As{
public:
As(
const std::vector<A>& sub_collec_
);
private:
std::vector<A> sub_collec;//[3]
};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(impl_.clone()){};
A::A(const A& o):pimpl((o.pimpl)->clone()){};
A& A::eek:perator=(const A& rhs){
if(&rhs!=this){
pimpl=rhs.pimpl->clone();
};
return *this;
};
#include "As.h"
As::As(
const std::vector<A>& sub_collec_
): sub_collec(sub_collec_){};//[4]


instantiated from 'void std::_Destroy(_Tp*) [with _Tp = A]'
testing_vector_pimpl A.h line 6 1191008360119 128231
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::__destroy_aux(_ForwardIterator, _ForwardIterator, __false_type)
[with _ForwardIterator = A*]' testing_vector_pimpl line 122
1191008360120 128232
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator, std::allocator<_T2>)
[with _ForwardIterator = A*, _Tp = A]' testing_vector_pimpl line 182
1191008360120 128234
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator = A*]' testing_vector_pimpl line 155 1191008360120
128233
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_vector.h instantiated from 'std::vector<_Tp, _Alloc>::~vector()
[with _Tp = A, _Alloc = std::allocator<A>]' testing_vector_pimpl line
272 1191008360120 128235
 
B

Barry

er said:
hi,

the code below generates the following behavior. cld someone please
help understand it?

don't say generate behavior, I see that's compiler-time error, behavior
much more means that the code runs expectedly.
1) clean project + build project generates build errors (see bottom)
2) build a second time, errors disappears, run: ok

that's more about the compiler, not about C++ language, I know that VC6
has some problems here.
3) uncomment [1] and comment [2], no problem
4) uncomment [3] and [4], also no problem

#ifndef A_IMPL_H_
#define A_IMPL_H_
#include <memory>
class A_impl{
public:
A_impl();
virtual ~A_impl(){};
virtual std::auto_ptr<A_impl> clone()const=0;
private:
A_impl& operator=(const A_impl&);
};
#endif /*A_IMPL_H_*/

#ifndef A_H_
#define A_H_
#include <memory>
//#include "A_impl.h" // [1]
class A_impl;//[2]
class A{
public:
A(const A_impl& impl_);
A(const A& o);
A& operator=(const A& rhs);

dtor is produced by compiler, it's

~A() {}

where std::auto_ptr::~auto_ptr() is called, which delete A_impl*, but
A_impl is incomplete type, if we only use forward declaration here. A
solution, declaration A::~A, and define it it *A.cpp*, where you include
"A_impl.h", so, A_impl is complete type there.

private:
A();
std::auto_ptr<A_impl> pimpl;
};
#endif /*A_H_*/

#ifndef AS_H_
#define AS_H_
#include <vector>
#include "A.h"
class As{
public:
As(
const std::vector<A>& sub_collec_
);
private:
std::vector<A> sub_collec;//[3]
};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(impl_.clone()){};
A::A(const A& o):pimpl((o.pimpl)->clone()){};
A& A::eek:perator=(const A& rhs){
if(&rhs!=this){
pimpl=rhs.pimpl->clone();
};
return *this;
};
#include "As.h"
As::As(
const std::vector<A>& sub_collec_
): sub_collec(sub_collec_){};//[4]


instantiated from 'void std::_Destroy(_Tp*) [with _Tp = A]'
testing_vector_pimpl A.h line 6 1191008360119 128231
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::__destroy_aux(_ForwardIterator, _ForwardIterator, __false_type)
[with _ForwardIterator = A*]' testing_vector_pimpl line 122
1191008360120 128232
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator, std::allocator<_T2>)
[with _ForwardIterator = A*, _Tp = A]' testing_vector_pimpl line 182
1191008360120 128234
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator = A*]' testing_vector_pimpl line 155 1191008360120
128233
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_vector.h instantiated from 'std::vector<_Tp, _Alloc>::~vector()
[with _Tp = A, _Alloc = std::allocator<A>]' testing_vector_pimpl line
272 1191008360120 128235
 
Y

yanlinlin82

hi,

the code below generates the following behavior. cld someone please
help understand it?
1) clean project + build project generates build errors (see bottom)

build error because you used undefined class A_impl (with [1]
commented and [2] uncommented at the first time).
2) build a second time, errors disappears, run: ok

I have no idea how can you run the program when build still error.
3) uncomment [1] and comment [2], no problem

When this done, class A_impl has been defined before you use it, of
course OK.
4) uncomment [3] and [4], also no problem

When this done, class A_impl is used only as a type (for pointer). It
needn't declare its detail, 'class A_impl;' is enough.
#ifndef A_IMPL_H_
#define A_IMPL_H_
#include <memory>
class A_impl{
public:
A_impl();
virtual ~A_impl(){};
virtual std::auto_ptr<A_impl> clone()const=0;
private:
A_impl& operator=(const A_impl&);};

#endif /*A_IMPL_H_*/

#ifndef A_H_
#define A_H_
#include <memory>
//#include "A_impl.h" // [1]
class A_impl;//[2]
class A{
public:
A(const A_impl& impl_);
A(const A& o);
A& operator=(const A& rhs);
private:
A();
std::auto_ptr<A_impl> pimpl;};

#endif /*A_H_*/

#ifndef AS_H_
#define AS_H_
#include <vector>
#include "A.h"
class As{
public:
As(
const std::vector<A>& sub_collec_
);
private:
std::vector<A> sub_collec;//[3]};

#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(impl_.clone()){};
A::A(const A& o):pimpl((o.pimpl)->clone()){};
A& A::eek:perator=(const A& rhs){
if(&rhs!=this){
pimpl=rhs.pimpl->clone();
};
return *this;};

#include "As.h"
As::As(
const std::vector<A>& sub_collec_
): sub_collec(sub_collec_){};//[4]

instantiated from 'void std::_Destroy(_Tp*) [with _Tp = A]'
testing_vector_pimpl A.h line 6 1191008360119 128231
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::__destroy_aux(_ForwardIterator, _ForwardIterator, __false_type)
[with _ForwardIterator = A*]' testing_vector_pimpl line 122
1191008360120 128232
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator, std::allocator<_T2>)
[with _ForwardIterator = A*, _Tp = A]' testing_vector_pimpl line 182
1191008360120 128234
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator = A*]' testing_vector_pimpl line 155 1191008360120
128233
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_vector.h instantiated from 'std::vector<_Tp, _Alloc>::~vector()
[with _Tp = A, _Alloc = std::allocator<A>]' testing_vector_pimpl line
272 1191008360120 128235
 
E

er

er said:
the code below generates the following behavior. cld someone please
help understand it?

don't say generate behavior, I see that's compiler-time error, behavior
much more means that the code runs expectedly.
1) clean project + build project generates build errors (see bottom)
2) build a second time, errors disappears, run: ok

that's more about the compiler, not about C++ language, I know that VC6
has some problems here.


3) uncomment [1] and comment [2], no problem
4) uncomment [3] and [4], also no problem
#ifndef A_IMPL_H_
#define A_IMPL_H_
#include <memory>
class A_impl{
public:
A_impl();
virtual ~A_impl(){};
virtual std::auto_ptr<A_impl> clone()const=0;
private:
A_impl& operator=(const A_impl&);
};
#endif /*A_IMPL_H_*/
#ifndef A_H_
#define A_H_
#include <memory>
//#include "A_impl.h" // [1]
class A_impl;//[2]
class A{
public:
A(const A_impl& impl_);
A(const A& o);
A& operator=(const A& rhs);

dtor is produced by compiler, it's

~A() {}

where std::auto_ptr::~auto_ptr() is called, which delete A_impl*, but
A_impl is incomplete type, if we only use forward declaration here. A
solution, declaration A::~A, and define it it *A.cpp*, where you include
"A_impl.h", so, A_impl is complete type there.


private:
A();
std::auto_ptr<A_impl> pimpl;
};
#endif /*A_H_*/
#ifndef AS_H_
#define AS_H_
#include <vector>
#include "A.h"
class As{
public:
As(
const std::vector<A>& sub_collec_
);
private:
std::vector<A> sub_collec;//[3]
};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(impl_.clone()){};
A::A(const A& o):pimpl((o.pimpl)->clone()){};
A& A::eek:perator=(const A& rhs){
if(&rhs!=this){
pimpl=rhs.pimpl->clone();
};
return *this;
};
#include "As.h"
As::As(
const std::vector<A>& sub_collec_
): sub_collec(sub_collec_){};//[4]
instantiated from 'void std::_Destroy(_Tp*) [with _Tp = A]'
testing_vector_pimpl A.h line 6 1191008360119 128231
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::__destroy_aux(_ForwardIterator, _ForwardIterator, __false_type)
[with _ForwardIterator = A*]' testing_vector_pimpl line 122
1191008360120 128232
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator, std::allocator<_T2>)
[with _ForwardIterator = A*, _Tp = A]' testing_vector_pimpl line 182
1191008360120 128234
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator = A*]' testing_vector_pimpl line 155 1191008360120
128233
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_vector.h instantiated from 'std::vector<_Tp, _Alloc>::~vector()
[with _Tp = A, _Alloc = std::allocator<A>]' testing_vector_pimpl line
272 1191008360120 128235

declaring ~A() in .h and writing A::~A(){} in .cpp did solve my
problem. thanks!
 
J

James Kanze

the code below generates the following behavior. cld someone please
help understand it?
1) clean project + build project generates build errors (see bottom)
2) build a second time, errors disappears, run: ok
3) uncomment [1] and comment [2], no problem
4) uncomment [3] and [4], also no problem
#ifndef A_IMPL_H_
#define A_IMPL_H_
#include <memory>
class A_impl{
public:
A_impl();
virtual ~A_impl(){};
virtual std::auto_ptr<A_impl> clone()const=0;
private:
A_impl& operator=(const A_impl&);};
#endif /*A_IMPL_H_*/
#ifndef A_H_
#define A_H_
#include <memory>
//#include "A_impl.h" // [1]
class A_impl;//[2]
class A{
public:
A(const A_impl& impl_);
A(const A& o);
A& operator=(const A& rhs);
private:
A();
std::auto_ptr<A_impl> pimpl;};
#endif /*A_H_*/

The line with std::auto_ptr<> is undefined behavior (with the
code as written). According to the standard, you can only
instantiate a template in the standard library over a completely
defined type.
#ifndef AS_H_
#define AS_H_
#include <vector>
#include "A.h"
class As{
public:
As(
const std::vector<A>& sub_collec_
);
private:
std::vector<A> sub_collec;//[3]};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(impl_.clone()){};
A::A(const A& o):pimpl((o.pimpl)->clone()){};
A& A::eek:perator=(const A& rhs){
if(&rhs!=this){
pimpl=rhs.pimpl->clone();
};
return *this;};
#include "As.h"
As::As(
const std::vector<A>& sub_collec_
): sub_collec(sub_collec_){};//[4]
instantiated from 'void std::_Destroy(_Tp*) [with _Tp = A]'
testing_vector_pimpl A.h line 6 1191008360119 128231
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::__destroy_aux(_ForwardIterator, _ForwardIterator, __false_type)
[with _ForwardIterator = A*]' testing_vector_pimpl line 122
1191008360120 128232
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator, std::allocator<_T2>)
[with _ForwardIterator = A*, _Tp = A]' testing_vector_pimpl line 182
1191008360120 128234
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_construct.h instantiated from 'void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator = A*]' testing_vector_pimpl line 155 1191008360120
128233
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
stl_vector.h instantiated from 'std::vector<_Tp, _Alloc>::~vector()
[with _Tp = A, _Alloc = std::allocator<A>]' testing_vector_pimpl line
272 1191008360120 128235

I don't know exactly why the rebuild eliminates the error with
g++. With some other compilers, however, template
instantiations are stored in a repository; if the template is
successfully instantiated in another translation unit, then the
rebuild will work.

But it doesn't really matter. You have undefined behavior, and
you should fix it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top