473,664 Members | 3,001 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

vector of pimpl's / weird behavior

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 _implclone()con st=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 _implpimpl;
};
#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<Asu b_collec;//[3]
};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(im pl_.clone()){};
A::A(const A& o):pimpl((o.pim pl)->clone()){};
A& A::operator=(co nst 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(_ForwardIte rator, _ForwardIterato r, __false_type)
[with _ForwardIterato r = 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 , _ForwardIterato r, std::allocator< _T2>)
[with _ForwardIterato r = 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 , _ForwardIterato r) [with
_ForwardIterato r = 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<_T p, _Alloc>::~vecto r()
[with _Tp = A, _Alloc = std::allocator< A>]' testing_vector_ pimpl line
272 1191008360120 128235

Sep 28 '07 #1
4 1613
er wrote:
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 _implclone()con st=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 _implpimpl;
};
#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<Asu b_collec;//[3]
};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(im pl_.clone()){};
A::A(const A& o):pimpl((o.pim pl)->clone()){};
A& A::operator=(co nst 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(_ForwardIte rator, _ForwardIterato r, __false_type)
[with _ForwardIterato r = 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 , _ForwardIterato r, std::allocator< _T2>)
[with _ForwardIterato r = 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 , _ForwardIterato r) [with
_ForwardIterato r = 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<_T p, _Alloc>::~vecto r()
[with _Tp = A, _Alloc = std::allocator< A>]' testing_vector_ pimpl line
272 1191008360120 128235

--
Thanks
Barry
Sep 29 '07 #2
On 9 29 , 3 49 , er <erwann.rog...@ gmail.comwrote:
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 _implclone()con st=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 _implpimpl;};

#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<Asu b_collec;//[3]};

#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(im pl_.clone()){};
A::A(const A& o):pimpl((o.pim pl)->clone()){};
A& A::operator=(co nst 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(_ForwardIte rator, _ForwardIterato r, __false_type)
[with _ForwardIterato r = 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 , _ForwardIterato r, std::allocator< _T2>)
[with _ForwardIterato r = 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 , _ForwardIterato r) [with
_ForwardIterato r = 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<_T p, _Alloc>::~vecto r()
[with _Tp = A, _Alloc = std::allocator< A>]' testing_vector_ pimpl line
272 1191008360120 128235

Sep 29 '07 #3
er
On Sep 29, 8:08 am, Barry <dhb2...@gmail. comwrote:
er wrote:
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 _implclone()con st=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 _implpimpl;
};
#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<Asu b_collec;//[3]
};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(im pl_.clone()){};
A::A(const A& o):pimpl((o.pim pl)->clone()){};
A& A::operator=(co nst 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(_ForwardIte rator, _ForwardIterato r, __false_type)
[with _ForwardIterato r = 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 , _ForwardIterato r, std::allocator< _T2>)
[with _ForwardIterato r = 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 , _ForwardIterato r) [with
_ForwardIterato r = 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<_T p, _Alloc>::~vecto r()
[with _Tp = A, _Alloc = std::allocator< A>]' testing_vector_ pimpl line
272 1191008360120 128235

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

Sep 30 '07 #4
On Sep 28, 9:49 pm, er <erwann.rog...@ gmail.comwrote:
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 _implclone()con st=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 _implpimpl;};
#endif /*A_H_*/
The line with std::auto_ptr<i s 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<Asu b_collec;//[3]};
#endif /*AS_H_*/
#include "A.h"
#include "A_impl.h"
A::A(const A_impl& impl_):pimpl(im pl_.clone()){};
A::A(const A& o):pimpl((o.pim pl)->clone()){};
A& A::operator=(co nst 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(_ForwardIte rator, _ForwardIterato r, __false_type)
[with _ForwardIterato r = 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 , _ForwardIterato r, std::allocator< _T2>)
[with _ForwardIterato r = 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 , _ForwardIterato r) [with
_ForwardIterato r = 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<_T p, _Alloc>::~vecto r()
[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.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Oct 1 '07 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
7861
by: Icosahedron | last post by:
I've been going through some old code trying to clean it up and rearchitect it based on more modern C++ idioms. In the old code I often used the Pimpl idiom on a class by class basis, creating impl within a class as such: a.h class A { ...stuff... struct AImpl; AImpl* _impl;
6
2185
by: Asfand Yar Qazi | last post by:
Hi, Now that GCC 3.4 has precompiled headers, I'm thinking I can stop using pimpls to speed up development time, as it may make life easier (declaring pimpls takes a long time...) What are the views of the experienced users of various C++ implementations? Do precompiled headers allow pimpls to be avoided while maintaining the same speed up of development time?
2
6108
by: Peteris Krumins | last post by:
Hello! I was playing around pimpl idiom and discovered that there is a problem with it if a class member template function exists which has to access private data, since only the forward declaration of pimpl class is provided. Example:
9
1554
by: Edward Diener | last post by:
Because 'friend' is not recognized in MC++, using the pImpl idiom in MC++ classes seems nearly impossible. Normally a pImpl class is a 'friend' to the class for which it supplies the private implementation, so that it can access any protected members, including inherited protected members, of that class. Without 'friend' the pImpl class can no longer do this, and it is a PITA passing the necessary protected data or protected member function...
10
4485
by: red floyd | last post by:
It seems that the use of auto_ptr<> is discouraged in many places in favor of boost::shared_ptr<> (or tr1::shared_ptr<>). But consider a PIMPL idiom, where there is a strict 1-1 relationship between interface objects and implementation object, and the implementation object lasts for the lifetime of the interface object. i.e. // header file class WidgetImpl; class Widget {
34
3689
by: Asfand Yar Qazi | last post by:
Hi, I'm creating a library where several classes are intertwined rather tightly. I'm thinking of making them all use pimpls, so that these circular dependancies can be avoided easily, and I'm thinking of making all these pimpl class declarations public. Reasoning is that since only the code within the ..cc file will need to ever access them, why protect them in ways that would make access to them more difficult and obfuscated? What...
14
3160
by: Daniel Lidström | last post by:
Hello! I have just discovered a way to use the private implementation idiom (pimpl), without the overhead of dynamic memory allocation. For those of you who don't know what this is, Wikipedia has a nice article you can read. Anyway, I discovered that if you make all members in the implementation class mutable, you can in fact use this idiom without any "unnecessary" memory allocation. Here's a minimal example of the method: // In the...
2
2223
by: Graham Reitz | last post by:
What are good strategies for selecting, either at run-time or compile time, various pimpl'ed implementations? While retaining the ability to switch implementations without recompiling. Boost has an example but with only one implementation class: (what would an example with 2 implementation classes look like?) http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html#pimpl The pimpl'ed class cpp file has to include at...
7
2670
by: Ralf Goertz | last post by:
Hi, the following templated code doesn't compile. It gives the error: template_it.cc:17: error: type 'std::vector<Derived1<T>*, std::allocator<Derived1<T>*' is not derived from type 'Derived2<T>' template_it.cc:17: error: expected ';' before 'vi' However, the same code compiles fine when I don't use any templates.
0
8437
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8348
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8861
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8549
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
7375
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
4185
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4351
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2003
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1759
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.