To my understanding, std::vector does not use reference counting to avoid
the overhead of copying and initialisation. Where can I get a reference
counted implementation of std::vector? Thanks. 27 5886
Jason Heyes wrote: To my understanding, std::vector does not use reference counting to avoid the overhead of copying and initialisation. Where can I get a reference counted implementation of std::vector? Thanks.
You might want to check out boost::shared_ptr.
Or, you could do somthing like this :
#include <vector>
template <typename T>
class vector_reference_counted
: public std::vector<T>
{
int m_reference_count;
public:
inline vector_reference_counted()
: m_reference_count( 1 )
{
}
inline vector_reference_counted( const vector_reference_counted &
i_rhs )
: m_reference_count( 1 ),
std::vector<T>( i_rhs )
{
}
inline vector_reference_counted & operator = ( const
vector_reference_counted & i_rhs )
{
// reference count does not change upon assignment
* static_cast< std::vector<T> * >( this ) = i_rhs;
return * this;
}
inline vector_reference_counted & operator = ( const std::vector<T>
& i_rhs )
{
// reference count does not change upon assignment
* static_cast< std::vector<T> * >( this ) = i_rhs;
return * this;
}
int AddRef()
{
int l_count = ++ m_reference_count;
return l_count;
}
int Release()
{
int l_count = -- m_reference_count;
if ( l_count == 0 )
{
delete this;
}
return l_count;
}
};
"Gianni Mariani" <gi*******@mariani.ws> wrote in message
news:br********@dispatch.concentric.net... Jason Heyes wrote: To my understanding, std::vector does not use reference counting to
avoid the overhead of copying and initialisation. Where can I get a reference counted implementation of std::vector? Thanks. You might want to check out boost::shared_ptr.
Why? I know about the shared_ptr. How does it help? Or, you could do somthing like this :
#include <vector>
template <typename T> class vector_reference_counted : public std::vector<T> {
int m_reference_count;
public:
inline vector_reference_counted() : m_reference_count( 1 ) { }
inline vector_reference_counted( const vector_reference_counted & i_rhs ) : m_reference_count( 1 ), std::vector<T>( i_rhs ) { }
inline vector_reference_counted & operator = ( const vector_reference_counted & i_rhs ) { // reference count does not change upon assignment
* static_cast< std::vector<T> * >( this ) = i_rhs;
return * this; }
inline vector_reference_counted & operator = ( const std::vector<T> & i_rhs ) { // reference count does not change upon assignment
* static_cast< std::vector<T> * >( this ) = i_rhs;
return * this; }
int AddRef() { int l_count = ++ m_reference_count;
return l_count; }
int Release() { int l_count = -- m_reference_count;
if ( l_count == 0 ) { delete this; }
return l_count; }
};
I don't see how that helps either. Please explain.
Jason Heyes wrote: "Gianni Mariani" <gi*******@mariani.ws> wrote in message news:br********@dispatch.concentric.net...
Jason Heyes wrote:
To my understanding, std::vector does not use reference counting to
I don't see how that helps either. Please explain.
Maybe you should explain what you're trying to do.
"Gianni Mariani" <gi*******@mariani.ws> wrote in message
news:br********@dispatch.concentric.net... Maybe you should explain what you're trying to do.
Here is a program that uses std::vector.
#include <algorithm>
#include <vector>
#include <iostream>
std::istream &read_nums(std::istream &is, std::vector<int> &nums)
{
while (is)
{
int num;
if (std::cin >> num)
nums.push_back(num);
}
return is;
}
int main()
{
std::vector<int> nums;
if (!read_nums(std::cin, nums))
return 1;
sort(nums.begin(), nums.end());
for (int i=0; i < nums.size(); i++)
os << nums[i] << endl;
return 0;
}
I want another class so I can change the above code into this.
#include <algorithm>
#include <iostream>
#include "SharedVector.h"
std::istream &read_nums(std::istream &is, SharedVector<int> &nums)
{
while (is)
{
int num;
if (std::cin >> num)
nums.push_back(num);
}
return is;
}
int main()
{
SharedVector<int> nums;
if (!read_nums(std::cin, nums))
return 1;
sort(nums.begin(), nums.end());
for (int i=0; i < nums.size(); i++)
os << nums[i] << endl;
return 0;
}
See how the code is exactly the same except that std::vector is replaced
with SharedVector? This is what I want to be able to do. I want a class that
replaces std::vector but does the same thing as std::vector and uses
reference counting in it's implementation. Is that possible?
"Jason Heyes" <ge******@optusnet.com.au> wrote in message
news:3f***********************@news.optusnet.com.a u To my understanding, std::vector does not use reference counting to avoid the overhead of copying and initialisation. Where can I get a reference counted implementation of std::vector? Thanks.
You might ask yourself whether you should be seeking such a thing. If
std::vector does not use reference counting, then it is probably for a good
reason. The following is from Josuttis (C++ Standard Library, p. 506):
"The primary goal of vectors is to handle and to manipulate the elements of
the container, not the container as a whole. Thus, vectors implementations
are optimized to operate on elements inside the container.
"The primary goal of strings is to handle and manipulate the container (the
string) as a whole. Thus, strings are optimized to reduce the costs of
assigning and passing the whole container.
"These different goals typically result in completely different
implementations. For example, strings are often implemented by using
reference counting: vectors never are."
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)
On Mon, 15 Dec 2003 18:50:03 +1100, "Jason Heyes"
<ge******@optusnet.com.au> wrote: See how the code is exactly the same except that std::vector is replaced with SharedVector? This is what I want to be able to do. I want a class that replaces std::vector but does the same thing as std::vector and uses reference counting in it's implementation. Is that possible?
It's possible, but I don't know of a free reference counted vector
implementation that conforms to the std::vector interface - it would
be easy to write one of course (though time consuming to code and
debug).
Note that in the posted code it would be a pessimization to have
reference counting. In the few cases where you do need it (to share
ownership of a vector), using a shared_ptr seems the obvious solution.
Why make a special case for a shared vector? int isn't shared...
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
> >I want a class that replaces std::vector but does the same thing as std::vector and uses reference counting in it's implementation. Is that possible?
It's possible, but I don't know of a free reference counted vector implementation that conforms to the std::vector interface - it would be easy to write one of course (though time consuming to code and debug).
Easy? Really? Just for curiosity, would you be planning to use the same
semantics as std::vector? If not, what would you change? If so, what would
be the interaction between, say, the "begin" member function and the
reference count?
"tom_usenet" <to********@hotmail.com> wrote in message
news:45********************************@4ax.com... On Mon, 15 Dec 2003 18:50:03 +1100, "Jason Heyes" <ge******@optusnet.com.au> wrote:See how the code is exactly the same except that std::vector is replaced with SharedVector? This is what I want to be able to do. I want a class
thatreplaces std::vector but does the same thing as std::vector and uses reference counting in it's implementation. Is that possible? It's possible, but I don't know of a free reference counted vector implementation that conforms to the std::vector interface - it would be easy to write one of course (though time consuming to code and debug).
On the face of things I think it should be ok if I write my own. Maybe not a
full-blown version but at least something useful for my current project.
Here is something that I wrote based on the public interface of std::vector.
template <class T> class SharedVector
{
SharedPtr<std::vector<T> > ptr;
public:
typedef std::vector<T>::size_type size_type;
typedef IteratorNotDefinedYet iterator;
typedef ConstIteratorNotDefinedYet const_iterator;
explicit SharedVector() : ptr(new std::vector<T>) { }
explicit SharedVector(size_type n, const T &v = T()) :
ptr(new std::vector<T>(n,v)) { }
SharedVector(const SharedVector &x) : ptr(x.ptr) { }
SharedVector(const_iterator first, const_iterator last) :
ptr(new std::vector<T>(first, last)) { }
iterator begin() { return iterator(ptr->begin()); }
const_iterator begin() const { return const_iterator(ptr->begin(),
ptr); }
iterator end() { return iterator(ptr->end()); }
const_iterator end() const { return const_iterator(ptr->end(), ptr); }
T &operator[](size_type pos)
{
ptr.make_unique(); // "copy-on-write" before calling non-const
method
return ptr->operator[](pos);
}
const T &operator[](size_type pos) const { return
ptr->operator[](pos); }
};
I haven't thought alot about allocators, iterators or anything. Just the
obvious things. Feel free to point out what is wrong in the above design. Note that in the posted code it would be a pessimization to have reference counting. In the few cases where you do need it (to share ownership of a vector), using a shared_ptr seems the obvious solution. Why make a special case for a shared vector? int isn't shared...
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Perhaps "SharedVector" isn't the right term. I thought of referring to it as
"VectorRef" instead but I changed my mind. Anyway I certainly believe that a
SharedVector would be much more convenient than a SharedPtr alone. Let me
write another example to make this clear.
class Book
{
std::string title;
SharedVector<Page> pages;
public:
Book(std::string title_, SharedVector<Page> pages_) :
title(title_), pages(pages_) { }
void find(std::string line, SharedVector<Page> &pages_) const {
for (int i=0; i < pages.size(); i++) {
if (pages[i].contains(line))
pages_.push_back(pages[i]);
}
}
friend std::istream &operator>>(std::istream &, Book &);
};
class Page
{
int number;
SharedVector<std::string> lines;
public:
bool contains(std::string line) const
{ return find(lines.begin(), lines.end(), line) != lines.end(); }
friend std::ostream &operator<<(std::ostream &, const Page &);
friend std::istream &operator>>(std::istream &, Page &);
};
using namespace std;
int main()
{
// read book from cin
Book book;
if (!(cin >> book))
return 1;
// find pages that contain the line "foo"
SharedVector<Page> pages;
book.find("foo", pages);
// make another book with them and call it "the story of foo"
Book another_book("the story of foo", pages);
// display the pages using const_iterators, so they stay shared
const SharedVector<Page> &const_pages = pages;
copy(const_pages.begin(), const_pages.end(),
ostream_iterator<Page>(cout, "\n"));
return 0;
};
"John Carson" <do***********@datafast.net.au> wrote in message
news:3f********@usenet.per.paradox.net.au... You might ask yourself whether you should be seeking such a thing. If std::vector does not use reference counting, then it is probably for a
good reason. The following is from Josuttis (C++ Standard Library, p. 506):
"The primary goal of vectors is to handle and to manipulate the elements
of the container, not the container as a whole. Thus, vectors implementations are optimized to operate on elements inside the container.
"The primary goal of strings is to handle and manipulate the container
(the string) as a whole. Thus, strings are optimized to reduce the costs of assigning and passing the whole container.
"These different goals typically result in completely different implementations. For example, strings are often implemented by using reference counting: vectors never are."
-- John Carson 1. To reply to email address, remove donald 2. Don't reply to email address (post here instead)
Interesting. I will need to think about this. Would you use a vector, say,
to store pixel information about an image? Or would you use a string
instead? Consider:
class Image
{
std::vector<Pixel> pixels;
public:
// an example of a costly operation
Image(const Image &image) : pixels(image.pixels) { }
// other image operations
};
What do you think? Should I have used a string instead of a vector? I'm
confused.
Jason Heyes wrote: Interesting. I will need to think about this. Would you use a vector, say, to store pixel information about an image? Or would you use a string instead? Consider:
Can't talk for John but I know that I wouldn't use a string.
I associate different functionality with something called a string. class Image { std::vector<Pixel> pixels; public: // an example of a costly operation Image(const Image &image) : pixels(image.pixels) { }
// other image operations };
What do you think? Should I have used a string instead of a vector? I'm confused.
In cases like this, when I want to emphasize to the user of the class
that this is a costly operation and that he should rethink if he really
wants to do that (or if he simply made a typo) I do:
class Image
{
public:
...
void CopyTo( Image& To );
private:
Image( const Image& Arg ); // not implemented, use CopyTo instead
Image& operator=( const Image& Arg ); // not implemented, use CopyTo instead
std::vector< Pixel > pixels;
};
In other words: I disable the copy constructor and the assigment operator
(assignment operator is debatable) and force the user to explicitely ask
for a copy if he wants one.
--
Karl Heinz Buchegger kb******@gascad.at
"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F**************@gascad.at... Jason Heyes wrote: Interesting. I will need to think about this. Would you use a vector,
say, to store pixel information about an image? Or would you use a string instead? Consider: Can't talk for John but I know that I wouldn't use a string. I associate different functionality with something called a string.
class Image { std::vector<Pixel> pixels; public: // an example of a costly operation Image(const Image &image) : pixels(image.pixels) { }
// other image operations };
What do you think? Should I have used a string instead of a vector? I'm confused.
In cases like this, when I want to emphasize to the user of the class that this is a costly operation and that he should rethink if he really wants to do that (or if he simply made a typo) I do:
class Image { public: ... void CopyTo( Image& To );
private: Image( const Image& Arg ); // not implemented, use CopyTo
instead Image& operator=( const Image& Arg ); // not implemented, use CopyTo
instead std::vector< Pixel > pixels; };
In other words: I disable the copy constructor and the assigment operator (assignment operator is debatable) and force the user to explicitely ask for a copy if he wants one.
-- Karl Heinz Buchegger kb******@gascad.at
That looks like the best solution but it gets annoying when other classes
need Image as a member. Consider the Student class for example. Because
Image is not copy-constructible, Student needs CopyTo().
class Student
{
std::string name;
Image picture;
// ...
public:
void CopyTo(Student &To)
{
To.name = name;
picture.CopyTo(To.picture);
}
};
I guess if you get in the habit of it, it isn't so bad.
On Mon, 15 Dec 2003 13:37:57 GMT, "Andrew Koenig" <ar*@acm.org> wrote: >I want a class that >replaces std::vector but does the same thing as std::vector and uses >reference counting in it's implementation. Is that possible?
It's possible, but I don't know of a free reference counted vector implementation that conforms to the std::vector interface - it would be easy to write one of course (though time consuming to code and debug).
Easy? Really? Just for curiosity, would you be planning to use the same semantics as std::vector? If not, what would you change? If so, what would be the interaction between, say, the "begin" member function and the reference count?
template <class T, class Alloc=...>
class shared_vector
{
shared_ptr<vector<T, Alloc> > m_impl;
public:
//duplicate vector interface, forwarding to m_impl.
//exceptions are copy constructor and assignment and destructor
//which should be compiler generated ones.
};
Semantics are slightly different from std::vector. Basically,
modifications/invalidations of any of the shared copies affect all
iterators/references into any of the copies.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
On Tue, 16 Dec 2003 04:31:47 +1100, "Jason Heyes"
<ja********@optusnet.com.au> wrote: That looks like the best solution but it gets annoying when other classes need Image as a member. Consider the Student class for example. Because Image is not copy-constructible, Student needs CopyTo().
class Student { std::string name; Image picture; // ... public: void CopyTo(Student &To) { To.name = name; picture.CopyTo(To.picture); } };
I guess if you get in the habit of it, it isn't so bad.
What does copying a student mean? Cloning is still a technology in its
infancy. IOW, most application domain classes shouldn't be copyable.
Only "value-type" classes (that act like "int") need be copyable.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jason Heyes wrote: That looks like the best solution but it gets annoying when other classes need Image as a member. Consider the Student class for example. Because Image is not copy-constructible, Student needs CopyTo().
class Student { std::string name; Image picture; // ... public: void CopyTo(Student &To) { To.name = name; picture.CopyTo(To.picture); } };
I guess if you get in the habit of it, it isn't so bad.
It depends ?
The problem is that it is easy to forget about the '&' in an argument
list:
void foo( Student Arg )
{
do something with Arg
}
Well. This creates a copy of the callers student. But since copying
is a costly operation (a strudent contains an image) you might want
to not allow this automtically. Now the programmer has the choice: If he
is willing to spend the time for creating the copy, he can do so, or he
can rething if the above shouldn't read:
void foo( Student& Arg )
{
}
If the hiding of cctor is a good idea or not may vary by your
milage. Sometimes I do it (if the copying is *really* expensive),
sometimes I don't.
--
Karl Heinz Buchegger kb******@gascad.at
"tom_usenet" <to********@hotmail.com> wrote in message
news:3s********************************@4ax.com... template <class T, class Alloc=...> class shared_vector { shared_ptr<vector<T, Alloc> > m_impl; public: //duplicate vector interface, forwarding to m_impl. //exceptions are copy constructor and assignment and destructor //which should be compiler generated ones. };
Semantics are slightly different from std::vector. Basically, modifications/invalidations of any of the shared copies affect all iterators/references into any of the copies.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
When would you use a shared_vector (if ever) and why?
"tom_usenet" <to********@hotmail.com> wrote in message
news:b6********************************@4ax.com... What does copying a student mean? Cloning is still a technology in its infancy. IOW, most application domain classes shouldn't be copyable. Only "value-type" classes (that act like "int") need be copyable.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Is there really a distinction between an int and a Student? They're both
objects, aren't they?
"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F***************@gascad.at... It depends ?
The problem is that it is easy to forget about the '&' in an argument list:
void foo( Student Arg ) { do something with Arg }
Well. This creates a copy of the callers student. But since copying is a costly operation (a strudent contains an image) you might want to not allow this automtically. Now the programmer has the choice: If he is willing to spend the time for creating the copy, he can do so, or he can rething if the above shouldn't read:
void foo( Student& Arg ) { }
If the hiding of cctor is a good idea or not may vary by your milage. Sometimes I do it (if the copying is *really* expensive), sometimes I don't.
-- Karl Heinz Buchegger kb******@gascad.at
Take the following class:
class Image
{
SharedVector<Pixel> pixels;
// ...
};
and assume it uses compiler-generated constructors. What does it really mean
to make a copy of an Image? It is no longer a costly operation but consider
what happens when the Image is mutated.
void Image::negate()
{
pixels.make_unique(); // copying may take place here
SharedVector<Pixel>::size_type i;
for (i=0; i < pixels.size(); i++)
pixels[i].negate();
}
Now Image::negate is potentially a costly operation. What do you think?
On Tue, 16 Dec 2003 16:55:57 +1100, "Jason Heyes"
<ja********@optusnet.com.au> wrote: "tom_usenet" <to********@hotmail.com> wrote in message news:3s********************************@4ax.com.. . template <class T, class Alloc=...> class shared_vector { shared_ptr<vector<T, Alloc> > m_impl; public: //duplicate vector interface, forwarding to m_impl. //exceptions are copy constructor and assignment and destructor //which should be compiler generated ones. };
Semantics are slightly different from std::vector. Basically, modifications/invalidations of any of the shared copies affect all iterators/references into any of the copies.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
When would you use a shared_vector (if ever) and why?
I wouldn't! I'd use a shared_ptr<vector>, since shared_vector is just
syntatic sugar.
Writing a COW shared_vector as you propose that doesn't have
surprising behaviour is not easy - it's not clear what the semantics
should be. To get the "correct" semantics working requires very
conservative sharing, which rather defeats the point...
e.g.
shared_vector<T> v1;
//...
shared_vector<T> v2 = v1; //shared
shared_vector<T> const& v2ref = v2;
T const& t = v2ref[0]; //does this unshare?
assert(v2[0] == v2ref[0]); //this should clearly work!
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
On Tue, 16 Dec 2003 18:05:31 +1100, "Jason Heyes"
<ja********@optusnet.com.au> wrote: Take the following class:
class Image { SharedVector<Pixel> pixels; // ... };
and assume it uses compiler-generated constructors. What does it really mean to make a copy of an Image? It is no longer a costly operation but consider what happens when the Image is mutated.
void Image::negate() { pixels.make_unique(); // copying may take place here
SharedVector<Pixel>::size_type i; for (i=0; i < pixels.size(); i++) pixels[i].negate(); }
Now Image::negate is potentially a costly operation. What do you think?
I think Image should be non-copyable, but have a "clone" operation if
you need one.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
"tom_usenet" <to********@hotmail.com> wrote in message
news:fg********************************@4ax.com... On Tue, 16 Dec 2003 16:55:57 +1100, "Jason Heyes" <ja********@optusnet.com.au> wrote:When would you use a shared_vector (if ever) and why?
I wouldn't! I'd use a shared_ptr<vector>, since shared_vector is just syntatic sugar.
Writing a COW shared_vector as you propose that doesn't have surprising behaviour is not easy - it's not clear what the semantics should be. To get the "correct" semantics working requires very conservative sharing, which rather defeats the point...
e.g.
shared_vector<T> v1; //... shared_vector<T> v2 = v1; //shared shared_vector<T> const& v2ref = v2; T const& t = v2ref[0]; //does this unshare? assert(v2[0] == v2ref[0]); //this should clearly work!
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
shared_vector<T> v1;
//...
shared_vector<T> v2 = v1; //shared yes
shared_vector<T> const& v2ref = v2;
T const& t = v2ref[0]; //does this unshare? No. v2ref is const
assert(v2[0] == v2ref[0]); //this should clearly work! Yes it does. v2 is
const within expression
// therefore const version of operator[] is called
// which means v2 does not unshare
Am I correct?
On Tue, 16 Dec 2003 23:05:46 +1100, "Jason Heyes"
<ja********@optusnet.com.au> wrote: shared_vector<T> v1; //... shared_vector<T> v2 = v1; //shared yes shared_vector<T> const& v2ref = v2; T const& t = v2ref[0]; //does this unshare? No. v2ref is const assert(v2[0] == v2ref[0]); //this should clearly work! Yes it does. v2 is const within expression // therefore const version of operator[] is called // which means v2 does not unshare
Am I correct?
No. non-const operator[] is called for non-const objects.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
On Tue, 16 Dec 2003 15:47:53 +0000, tom_usenet
<to********@hotmail.com> wrote: On Tue, 16 Dec 2003 23:05:46 +1100, "Jason Heyes" <ja********@optusnet.com.au> wrote:
shared_vector<T> v1; //... shared_vector<T> v2 = v1; //shared yes shared_vector<T> const& v2ref = v2; T const& t = v2ref[0]; //does this unshare? No. v2ref is const assert(v2[0] == v2ref[0]); //this should clearly work! Yes it does. v2 is const within expression // therefore const version of operator[] is called // which means v2 does not unshare
Am I correct?
No. non-const operator[] is called for non-const objects.
Whoops, and the assert was meant to be:
assert(&v2[0] == &v2ref[0]);
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jason Heyes wrote: Take the following class:
class Image { SharedVector<Pixel> pixels; // ... };
and assume it uses compiler-generated constructors. What does it really mean to make a copy of an Image? It is no longer a costly operation
What's SharedVector?
Is it some sort of reference counted vector?
I guess so. At least it is consistent with the following
but consider what happens when the Image is mutated.
void Image::negate() { pixels.make_unique(); // copying may take place here
SharedVector<Pixel>::size_type i; for (i=0; i < pixels.size(); i++) pixels[i].negate(); }
Now Image::negate is potentially a costly operation. What do you think?
It is a costly operation and may not be what the user of the class
expects. Personally I try to avoid such clever hacks. If the user requests
a copy, he gets a copy. He has a reason for requesting the copy and is willing
to pay the price for that at the moment he is requesting that copy.
But manipulation and copying are 2 different concepts. That's why I avoid
such things. But that's IMHO.
--
Karl Heinz Buchegger kb******@gascad.at
"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F***************@gascad.at... Jason Heyes wrote: Take the following class:
class Image { SharedVector<Pixel> pixels; // ... };
and assume it uses compiler-generated constructors. What does it really
mean to make a copy of an Image? It is no longer a costly operation What's SharedVector? Is it some sort of reference counted vector? I guess so. At least it is consistent with the following
Yeah basically. In other words, SharedVector is SharedPtr<std::vector> with
syntactic sugar. but consider what happens when the Image is mutated.
void Image::negate() { pixels.make_unique(); // copying may take place here
SharedVector<Pixel>::size_type i; for (i=0; i < pixels.size(); i++) pixels[i].negate(); }
Now Image::negate is potentially a costly operation. What do you think? It is a costly operation and may not be what the user of the class expects. Personally I try to avoid such clever hacks. If the user requests a copy, he gets a copy. He has a reason for requesting the copy and is
willing to pay the price for that at the moment he is requesting that copy. But manipulation and copying are 2 different concepts. That's why I avoid such things. But that's IMHO.
-- Karl Heinz Buchegger kb******@gascad.at
Yes it looks bad. Its just too much to assume that the user understands
copy-on-write. I know I don't. Do you think it would help if we renamed the
class to SharedImage? At least that way you make the user aware of what he
is playing with.
"tom_usenet" <to********@hotmail.com> wrote in message
news:ho********************************@4ax.com... On Tue, 16 Dec 2003 15:47:53 +0000, tom_usenet <to********@hotmail.com> wrote:No. non-const operator[] is called for non-const objects.
Whoops, and the assert was meant to be:
assert(&v2[0] == &v2ref[0]);
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Hehe. I never noticed that. I just assumed it meant that.
"tom_usenet" <to********@hotmail.com> wrote in message
news:i8********************************@4ax.com... On Tue, 16 Dec 2003 23:05:46 +1100, "Jason Heyes" <ja********@optusnet.com.au> wrote:
shared_vector<T> v1; //... shared_vector<T> v2 = v1; //shared yes shared_vector<T> const& v2ref = v2; T const& t = v2ref[0]; //does this unshare? No. v2ref is const assert(v2[0] == v2ref[0]); //this should clearly work! Yes it does. v2 is const within expression // therefore const version of operator[] is called // which means v2 does not unshare
Am I correct?
No. non-const operator[] is called for non-const objects.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
How about this design:
template <class T, class A = allocator<T> >
class shared_vector
{
shared_ptr<std::vector<T> > ptr;
public:
// duplicate public interface, forwarding to ptr
// exceptions are copy constructor and assignment and destructor
// which should be compiler generated ones.
// all mutators unshare except those that return an iterator or
reference
// a non-standard function to unshare
};
Here is the usage:
#include <algorithm>
#include <iostream>
#include "shared_vector.h"
std::istream &read_nums(std::istream &is, shared_vector<int> &nums)
{
while (is)
{
int num;
if (is >> num)
nums.push_back(num);
}
return is;
}
int main()
{
shared_vector<int> nums;
if (!read_nums(std::cin, nums))
return 1;
nums.push_back(-1); // vector is automatically unshared by this
operation
nums.unshare(); // manually unshare vector before indirect modification
sort(nums.begin(), nums.end());
for (int i=0; i < nums.size(); i++)
os << nums[i] << endl;
return 0;
}
The user must understand copy-on-write to use shared_vector properly. What
do you think?
On Wed, 17 Dec 2003 10:25:37 +1100, "Jason Heyes"
<ja********@optusnet.com.au> wrote: How about this design:
template <class T, class A = allocator<T> > class shared_vector { shared_ptr<std::vector<T> > ptr; public: // duplicate public interface, forwarding to ptr // exceptions are copy constructor and assignment and destructor // which should be compiler generated ones.
// all mutators unshare except those that return an iterator or reference
// a non-standard function to unshare
I think I might make mutators not unshare, and only unshare if the
explicit function is called. This might be less confusing.
};
Here is the usage:
#include <algorithm> #include <iostream> #include "shared_vector.h"
std::istream &read_nums(std::istream &is, shared_vector<int> &nums) { while (is) { int num; if (is >> num) nums.push_back(num); } return is; }
int main() { shared_vector<int> nums; if (!read_nums(std::cin, nums)) return 1;
nums.push_back(-1); // vector is automatically unshared by this operation
But there aren't any copies of num, so unsharing won't happen. I
suppose it's just an example. nums.unshare(); // manually unshare vector before indirect modification sort(nums.begin(), nums.end());
for (int i=0; i < nums.size(); i++) os << nums[i] << endl; return 0; }
The user must understand copy-on-write to use shared_vector properly. What do you think?
I don't see any benefits that outweigh the potential confusions. Users
tend to be confused by classes that do "clever" things behind their
backs, and prefer to have some control. My original example will still
break, and this might well cause confusion. Your shared_vector is
syntatic sugar that might be counter productive compared to an
explicit shared_ptr<vector> that everyone understands the semantics
of.
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: Anonymous |
last post by:
Is there a non-brute force method of doing this?
transform() looked likely but had no predefined function object.
std::vector<double> src;
std::vector<int> dest;
...
|
by: Michael Hopkins |
last post by:
Hi all
I want to create a std::vector that goes from 1 to n instead of 0 to n-1.
The only change this will have is in loops and when the vector returns
positions of elements etc. I am calling...
|
by: zl2k |
last post by:
hi, c++ user
Suppose I constructed a large array and put it in the std::vector in a
function and now I want to return it back to where the function is called.
I can do like this:
...
|
by: aaragon |
last post by:
I am trying to create a vector of type T and everything goes fine until
I try to iterate over it. For some reason, the compiler gives me an
error when I declare
std::vector<T>::iterator iter;...
|
by: imutate |
last post by:
How to directly reference i th element in std::vector (i being an
integer) ?
Example:
std::vector<doublex;
x.push_back(3);
x.push_back(-2);
x.push_back(-2);
x.push_back(-7);
int i = 3;
| |
by: lokchan |
last post by:
i want to create a vector of pointer s.t. it can handle new and delete
but also have std::vector interface
can i implement by partial specialization and inherence like follow ?
#include...
|
by: Lionel B |
last post by:
On my platform I find that the std::vector<boolspecialisation incurs a
significant performance hit in some circumstances (when compared, say, to
std::vector<intprogrammed analagously). Is it...
|
by: jubelbrus |
last post by:
Hi
I'm trying to do the following.
#include <vector>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/tuple/tuple.hpp>
class {
|
by: DevNull |
last post by:
I have a program where we load a mapfile, comprised of a .csv with
numbers which represent object types at a given position.
Each position is in the map is called a Cell, a cell contains only a...
|
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,...
|
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...
| |
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...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
|
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...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
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 ...
|
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |
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...
| |