ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Take the following bit of code. My first question is do explicit constructors prohibit using = in construction? GCC accepts this code, but Comeau online seems to want to construct the 'Consumable's by first creating an rvalue-'Consumable'. Does the C++ standard require () instead of = in this case?
My second question is what is your opinion of an object which is consumed by a function it is used in? In a library I'm building I use the pattern above using single-use objects that are consumed when passed to a function. This is a memory management measure: certain functions take/return a consumable object to allow the user to modify the structure of dynamic objects. The idea of the object is that a user can store one temporarily while they figure out where to put it, but if their temp goes out of scope then the enclosed pointer is deleted if the object hasn't been consumed by another function. In other words, a function returns a pointer to the user under the condition they return it to something "responsible". If they don't then that pointer will be deleted, and if they don't even store the return then it is destroyed at the end of the call. Thanks.
ta0kira
PS I am not using auto_ptr for these reasons:
1) basic lib will have no STL or explicit libc ties
2) cannot have an assignment operator due to ambiguity
3) only certain objects may release the pointer
4) the "don't delete me" criteria is type-specific
I would say g++ should not be allowing this to compile what compiler warning level are you using? also looks like you are reinventing a scoped pointer class.
[edit]
Here is copy of the scoped shared pointer class I use, you would need to adjust it if you wanted to use it tho as the release function releases it reference to the pointer not releases the actual pointer from the container to the user.
Code:
///////////////////////////////////////////////////////////////////////////////
/// shared_ptr.h
/// A very simple implementation of a shared scope pointer.
/// On going out of scope if decrements the counter so you must store it if
/// you want to use it later/
/// @remarks
/// It should look and feel like a normal pointer if you see anything
/// that does not seem correct, please let me know.
/// Warning!!!!!!!!!!!!!!!!
/// do not delete/null the pointer returned by ptr() you do not own it.
/// We could make it a T const* but this may cause problems????????????????
/// Added a release which will decrement the counter and delete if its zero.
/// @author Liam Devine @date 17/02/2007
/// update:
/// added static and dynamic casting
///////////////////////////////////////////////////////////////////////////////
#ifndef SHARED_PTR_H_
# define SHARED_PTR_H_
# include <cassert>
# include <stdexcept>
namespace LDR
{
//removed the ref counter to outside of the shared_ptr scope as
//when casting the raw underlying pointer it would require another cast
struct Counter
{
Counter():m_amount(0){}
int m_amount;
};
//forward declarations
template<typename T>class Shared_ptr;
template<typename TO,typename FROM>Shared_ptr<TO> sp_dynamic_cast(FROM rhs);
template<typename TO,typename FROM>Shared_ptr<TO> sp_static_cast(FROM rhs);
template<typename T>
class Shared_ptr
{
public:
//struct Counter
//{
// Counter():m_amount(0){}
// int m_amount;
//};
public:
Shared_ptr():m_ptr(0),m_count(0){}
Shared_ptr(T* pointer):m_ptr(pointer),m_count(new Counter)
{
assert(m_ptr && m_count);
++m_count->m_amount;
}
Shared_ptr(T* pointer, Counter* c):m_ptr(pointer),m_count(c)
{
assert(m_ptr && m_count);
++m_count->m_amount;
}
Shared_ptr(Shared_ptr<T> const& rhs):m_ptr(rhs.m_ptr),m_count(rhs.m_count)
{
assert(rhs.m_ptr && rhs.m_count);
++m_count->m_amount;
}
Shared_ptr<T>& operator = (Shared_ptr<T> const& rhs)
{
assert(rhs.m_ptr && rhs.m_count);
m_ptr = rhs.m_ptr;
m_count = rhs.m_count;
++m_count->m_amount;
return *this;
}
~Shared_ptr()
{
if(m_count)
{
if(m_count->m_amount>0)
{
--m_count->m_amount;
if(m_count->m_amount==0)
{
delete m_ptr;m_ptr=0;
delete m_count;m_count=0;
}
}
}
}
T* operator->()const
{
return m_ptr;
}
T& operator*()const
{
return *m_ptr;
}
T* ptr()const
{
return m_ptr;
}
T& ref()const
{
return *m_ptr;
}
bool operator ==(Shared_ptr<T> const& rhs)const
{
return m_ptr == rhs.m_ptr;
}
bool operator !=(Shared_ptr<T> const& rhs)const
{
return ! (m_ptr == rhs.m_ptr);
}
operator bool ()const
{
return m_ptr !=0;//&& m_count && m_count->m_amount != 0;
}
int count()const
{
return m_count ? m_count->m_amount : 0;
}
void release()
{
if(m_count)
{
if(m_count->m_amount > 0)
{
--m_count->m_amount;
}
else
{
delete m_count;
if(m_ptr)delete m_ptr;
}
m_count=0;
m_ptr=0;
}
}
private:
//casting friends
template<typename TO,typename FROM>friend Shared_ptr<TO> sp_dynamic_cast(FROM);
template<typename TO,typename FROM>friend Shared_ptr<TO> sp_static_cast(FROM);
T* m_ptr;
Counter* m_count;
};
template<typename TO,typename FROM>
Shared_ptr<TO> sp_static_cast(FROM rhs)
{
Shared_ptr<TO> r ( static_cast<TO*>( rhs.m_ptr),rhs.m_count );
return r;
}
template<typename TO,typename FROM>
Shared_ptr<TO> sp_dynamic_cast(FROM rhs)
{
TO* p = dynamic_cast<TO*>(rhs.m_ptr);
if(!p){ throw std::runtime_error("dynamic_cast error"); }
return Shared_ptr<TO> (p,rhs.m_count);
};
}
#endif//SHARED_PTR_H_
I am using -Wall and don't get any warnings (I rewrote this from memory but it's essentially the same.) I did find an answer for the first question: 'explicit' does require (), however I think the line 'Consumable Test3 = Transfer(Test2);' should implicitly call 'operator Consumable&()' (with GCC it does.)
I do need a custom class in this case because deletion is conditional based on the result of a virtual function called on the pointer. What I'd really like to know is if it's too non-standard that a 'Consumable' passed to a function is no longer usable. Again, I don't want any explicit external dependencies. Thanks.
ta0kira
PS A scoped pointer can't be copied, however I need mutating copying in the way auto_ptr has and no assignment operator (whether default or mutating.) A shared pointer is too much overhead and the reference counting is redundant in the case of my lib.
$ g++ taokira.cpp -Wall -ansi -pedantic -o taokira
taokira.cpp: In function `int main()':
taokira.cpp:36: error: conversion from `int*' to non-scalar type `Consumable' re
quested
Yes, I guess I mis-typed when rewriting that part (or maybe it's the -ansi that got me.) If you change that line to 'Consumable Test1(Value);' then it should work. My other questions/comments still stand, however. Thanks.
ta0kira
That was my reasoning for thinking it should not compile
Quote:
My second question is what is your opinion of an object which is consumed by a function it is used in?
You mean just like an auto_ptr ?
Quote:
In a library I'm building I use the pattern above using single-use objects that are consumed when passed to a function. This is a memory management measure: certain functions take/return a consumable object to allow the user to modify the structure of dynamic objects.
Consumable object have the requirement that they need to be passed by reference then yes?
Quote:
The idea of the object is that a user can store one temporarily while they figure out where to put it, but if their temp goes out of scope then the enclosed pointer is deleted if the object hasn't been consumed by another function.
Again just like an auto pointer
Quote:
In other words, a function returns a pointer to the user under the condition they return it to something "responsible". If they don't then that pointer will be deleted, and if they don't even store the return then it is destroyed at the end of the call. Thanks.
Yes I can understand why you don't want to use an auto_ptr (think maybe because of differing STL versions?) but it provides all the functionality you are after. So maybe you should try emulating the same sort of behaviour that auto_ptr has (similar to the code I shown), It's a wrapper for a pointer so there should be a bool operator, pointer operator etc so to the outside world it looks and feels just like a pointer and allows a user to typedef it and never have to worry about how different it is to a pointer.
Yes I can understand why you don't want to use an auto_ptr (think maybe because of differing STL versions?) but it provides all the functionality you are after. So maybe you should try emulating the same sort of behaviour that auto_ptr has (similar to the code I shown), It's a wrapper for a pointer so there should be a bool operator, pointer operator etc so to the outside world it looks and feels just like a pointer and allows a user to typedef it and never have to worry about how different it is to a pointer.
I've already got the bool, !, ->, and * implemented. It intentionally won't be transparent except for those functions, however (i.e. conversion-to-pointer operator and * return const) because they aren't supposed to use it as a pointer; just hold on to it long enough to place it somewhere else. The smart pointer will hold a node removed from a tree and allow the user to hang on to it while deciding where to reinsert it and is by no means meant to give them access to a real pointer (appropriate functions return a real pointer.) I'm going completely non-template here so I need to use an lvalue operator instead of returning a proxy class like auto_ptr. The main reason for not using auto_ptr is the assignment operators, its templated constructors, and a check I need to make in the destructor before deleting the pointer.
Quote:
Originally Posted by dmail
Consumable object have the requirement that they need to be passed by reference then yes?
The mutating copy constructor handles that (but requires the lvalue conversion operator when embedding function calls), but I'm thinking about changing to references just for clarity. That will cut down on a few copies, but isn't required.
ta0kira
It turns out the lvalue operator isn't actually used by stricter compilers (such as gcc 4.2.4 in Slackware 12.1-current,) so I just converted to a reference counter, anyway! It made me remember this discussion. The public interface only allows access to the const pointer and a friend class has access to the non-const version so that it can store it. The const-only public access prevents the developer from accidentally using the same pointer with two separate groups of reference-counting pointers. Before I was afraid that a smart pointer would go out of scope too soon, but it isn't a problem with the current library version. Thanks for the help, although very late!
ta0kira
Nevermind! It wasn't quite that simple. In multi-threaded applications, it's possible for a reference counter to hold a pointer to an object and have the object be deleted independently. Sort of just talking to myself, but I'm just giving an update.
ta0kira
The solution seems to be reference-counting smart pointers plus linked lists of the smart pointers. It's all very complex, but I guess that's the price of memory management!
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.