473,606 Members | 3,100 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Pimpl idiom without dynamic memory allocation

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
"unnecessar y" memory allocation. Here's a minimal example of the method:

// In the header of your class called Line

#include <string>

class Line
{
public:

Line(const std::string& name);
const std::string& GetName() const;
void SetName(const std::string& s);

private:

// Private implementation idiom:
// all member variables are hidden in this class
class LineImpl;
const LineImpl& m_pimpl; // normally a non-const pointer
};

// and in your implementation file:

#include "Line.h"

// Here we define the class with the member variables
class Line::LineImpl
{
public:

LineImpl(const std::string& s) : m_s(s) {}
// all methods need to be const here
const std::string& GetName() const { return m_s; }
void SetName(const std::string& s) const { m_s = s; }

private:

mutable std::string m_s; // the trick! all members are mutable
};

// create the pimpl instance without using new
Line::Line(cons t std::string& s) : m_pimpl(LineImp l(s)) {}

// forward all member functions to the private implementation
const std::string& Line::GetName() const
{
return m_pimpl.GetName ();
}

void Line::SetName(c onst std::string& s)
{
m_pimpl.SetName (s);
}

Ok experts, what do you all think? This method sacrifies
const-correctness for some extra speed. Is it worth it?

--
Daniel
Oct 17 '07 #1
14 3156
Daniel Lidström a écrit :
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
"unnecessar y" memory allocation. Here's a minimal example of the method:

// In the header of your class called Line

#include <string>

class Line
{
public:

Line(const std::string& name);
const std::string& GetName() const;
void SetName(const std::string& s);

private:

// Private implementation idiom:
// all member variables are hidden in this class
class LineImpl;
const LineImpl& m_pimpl; // normally a non-const pointer
};

// and in your implementation file:

#include "Line.h"

// Here we define the class with the member variables
[snip]
// all methods need to be const here
[snip]
mutable std::string m_s; // the trick! all members are mutable
Which mean you coerce the code into compilation. That's all.
// create the pimpl instance without using new
Line::Line(cons t std::string& s) : m_pimpl(LineImp l(s)) {}
Your local is destroyed when going out of scope. Doesn't it ?
[snip]
Ok experts, what do you all think? This method sacrifies
const-correctness for some extra speed. Is it worth it?
Not really.
And certainly not worth a dangling reference.
Michael
Oct 17 '07 #2
In article <47************ ***********@new s.free.fr>,
Michael DOUBEZ <mi************ @free.frwrote:
Daniel Lidström a écrit :
// create the pimpl instance without using new
Line::Line(cons t std::string& s) : m_pimpl(LineImp l(s)) {}

Your local is destroyed when going out of scope. Doesn't it ?
No it isn't. It is actually ok to bind a temporary object to a const
reference. There will be no "dangling" reference.

--
Daniel
Oct 17 '07 #3
Daniel Lidström a écrit :
In article <47************ ***********@new s.free.fr>,
Michael DOUBEZ <mi************ @free.frwrote:
>Daniel Lidström a écrit :
>>// create the pimpl instance without using new
Line::Line(co nst std::string& s) : m_pimpl(LineImp l(s)) {}
Your local is destroyed when going out of scope. Doesn't it ?

No it isn't. It is actually ok to bind a temporary object to a const
reference. There will be no "dangling" reference.
It is ok to bind it but that doesn't mean the lifetime of the temporary
is extended.

Example:
const std::string& foo()
{
return std::string("ba r");
}

The value returned by foo() is an dangling reference.

Michael

Oct 17 '07 #4
Daniel Lidström <so******@micro soft.comwrote:
// In the header of your class called Line

#include <string>

class Line
{
public:

Line(const std::string& name);
const std::string& GetName() const;
void SetName(const std::string& s);

private:

// Private implementation idiom:
// all member variables are hidden in this class
class LineImpl;
const LineImpl& m_pimpl; // normally a non-const pointer
};

// and in your implementation file:

#include "Line.h"

// Here we define the class with the member variables
class Line::LineImpl
{
public:

LineImpl(const std::string& s) : m_s(s) {}
// all methods need to be const here
const std::string& GetName() const { return m_s; }
void SetName(const std::string& s) const { m_s = s; }

private:

mutable std::string m_s; // the trick! all members are mutable
};

// create the pimpl instance without using new
Line::Line(cons t std::string& s) : m_pimpl(LineImp l(s)) {}
Where would the memory for the LineImpl object be placed? It isn't
embedded in the object, nor is it in the heap, and it can't be placed on
the stack (and still survive the call to the c_tor.)

Doesn't sound like a good idea to me.
Oct 17 '07 #5
Daniel Lidström wrote:
I have just discovered a way to use the private implementation idiom
(pimpl), without the overhead of dynamic memory allocation.
[ storing a reference to a temporary ]

As you noticed, this doesn't work. However, there is a method that works.
All you have to do is to add a suitably aligned and sufficiently large
buffer into the class:

class foo {
aligned_storage <42m_impl;
class implementation;
foo();
~foo();
void some_function() ;
};

class foo::implementa tion { ... };

foo::foo() {
// placement new
new m_impl.get<void >() implementation;
}
foo::~foo() {
// explicit dtor invokation
m_impl.get<impl ementation>()->~implementatio n;
}
void foo::some_funct ion() {
m_impl.get<impl ementation>()->some_function( );
}

Is it worth the hassle? Typically not, in particular since it's hard to
guarantee that you have both enough but still not too much memory.

Uli

Oct 18 '07 #6
On Oct 17, 10:36 pm, "Daniel T." <danie...@earth link.netwrote:
Daniel Lidström <someb...@micro soft.comwrote:
// In the header of your class called Line
#include <string>
class Line
{
public:
Line(const std::string& name);
const std::string& GetName() const;
void SetName(const std::string& s);
private:
// Private implementation idiom:
// all member variables are hidden in this class
class LineImpl;
const LineImpl& m_pimpl; // normally a non-const pointer
};
// and in your implementation file:
#include "Line.h"
// Here we define the class with the member variables
class Line::LineImpl
{
public:
LineImpl(const std::string& s) : m_s(s) {}
// all methods need to be const here
const std::string& GetName() const { return m_s; }
void SetName(const std::string& s) const { m_s = s; }
private:
mutable std::string m_s; // the trick! all members are mutable
};
// create the pimpl instance without using new
Line::Line(cons t std::string& s) : m_pimpl(LineImp l(s)) {}
Where would the memory for the LineImpl object be placed? It
isn't embedded in the object, nor is it in the heap, and it
can't be placed on the stack (and still survive the call to
the c_tor.)
>From the standard (§12.2/5): "A temporary bound to a reference
member in a constructor's ctor-initializer persists until the
constructor exits." In colloquial terms: the temporary is
created on the stack, and destructed before returning from the
constructor.
Doesn't sound like a good idea to me.
It isn't, unless you like undefined behavior and hard to find
bugs.

--
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 18 '07 #7
In article <47************ ***********@new s.free.fr>,
Michael DOUBEZ <mi************ @free.frwrote:
>Daniel Lidström a écrit :
>In article <47************ ***********@new s.free.fr>,
Michael DOUBEZ <mi************ @free.frwrote:
>>Daniel Lidström a écrit :
// create the pimpl instance without using new
Line::Line(c onst std::string& s) : m_pimpl(LineImp l(s)) {}
Your local is destroyed when going out of scope. Doesn't it ?

No it isn't. It is actually ok to bind a temporary object to a const
reference. There will be no "dangling" reference.

It is ok to bind it but that doesn't mean the lifetime of the temporary
is extended.

Example:
const std::string& foo()
{
return std::string("ba r");
}

The value returned by foo() is an dangling reference.
Euh, it's not what he is doing, it's more like:

std::string foo()
{
return std::string("ba r");
}

int main()
{
std::string const & val = foo();
....
Oct 18 '07 #8
Yannick Tremblay wrote:
In article <47************ ***********@new s.free.fr>,
Michael DOUBEZ <mi************ @free.frwrote:
>>Daniel Lidström a écrit :
>>In article <47************ ***********@new s.free.fr>,
Michael DOUBEZ <mi************ @free.frwrote:

Daniel Lidström a écrit :
// create the pimpl instance without using new
Line::Line( const std::string& s) : m_pimpl(LineImp l(s)) {}
Your local is destroyed when going out of scope. Doesn't it ?

No it isn't. It is actually ok to bind a temporary object to a const
reference. There will be no "dangling" reference.

It is ok to bind it but that doesn't mean the lifetime of the temporary
is extended.

Example:
const std::string& foo()
{
return std::string("ba r");
}

The value returned by foo() is an dangling reference.

Euh, it's not what he is doing, it's more like:

std::string foo()
{
return std::string("ba r");
}

int main()
{
std::string const & val = foo();
...
It's neither. What he is doing is initialzing a reference member from a
temporary object. The lifetime of that object lasts exactly to the end of
the constructor call. Afterwards, i.e., for the entire lifetime of the
fully constructed object, the reference is dangling. From the standard:

[...] A temporary bound to a reference member in a constructor?s
ctor-initializer (12.6.2) persists until the constructor exits. ...
[12.2/5]

This provision makes you wonder. What is the point of restricting the
life-time of the temporary to the duration of the constructor if the object
thus initialized is bound to have a dangling reference ever after?
Best

Kai-Uwe Bux
Oct 18 '07 #9
Kai-Uwe Bux <jk********@gmx .netwrote in
news:ff******** **@murdoch.acc. Virginia.EDU:
It's neither. What he is doing is initialzing a reference member from
a temporary object. The lifetime of that object lasts exactly to the
end of the constructor call. Afterwards, i.e., for the entire lifetime
of the fully constructed object, the reference is dangling. From the
standard:

[...] A temporary bound to a reference member in a constructor?s
ctor-initializer (12.6.2) persists until the constructor exits. ...
[12.2/5]

This provision makes you wonder. What is the point of restricting the
life-time of the temporary to the duration of the constructor if the
object thus initialized is bound to have a dangling reference ever
after?
It is interesting. I would have thought that it would last until the scope
in which the constructor was invoked exited and the stack space is
reclaimed. There is probably some case for creating the temporaries within
the scope of the constructor or something that I don't see at the moment.
In any case, I can't see this for the pimpl idiom.

joe
Oct 18 '07 #10

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
6107
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:
4
3514
by: Simon Elliott | last post by:
I want to design a class which will encapsulate some system specific representation, in this case time structs: #if unix_implementation #include <time.h> class Cfoo { private:
6
8197
by: chris | last post by:
Hi all, I need to know, what is the difference between dynamic memory allocation, and stack allocation ? 1. If I have a class named DestinationAddress, when should I use dynamic memory allocation to create object of that class ? 2. If it says "dynamic memory allocation", is it mean the following code : DestinationAddress* dest = new DestinationAddress(); // code 1
9
1553
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...
34
3685
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...
24
19063
by: Ken | last post by:
In C programming, I want to know in what situations we should use static memory allocation instead of dynamic memory allocation. My understanding is that static memory allocation like using array is faster than malloc, but dynamic memory allocation is more flexible. Please comment... thanks.
2
2221
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...
0
8036
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
7978
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
8461
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...
0
8448
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8126
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,...
1
5987
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4010
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2454
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
0
1313
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.