473,473 Members | 2,320 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Is there a reference counted implementation of std::vector?

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.
Jul 22 '05 #1
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;
}

};
Jul 22 '05 #2
"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.
Jul 22 '05 #3
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.

Jul 22 '05 #4
"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?
Jul 22 '05 #5
"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)

Jul 22 '05 #6
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
Jul 22 '05 #7
> >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?
Jul 22 '05 #8
"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;
};


Jul 22 '05 #9
"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.

Jul 22 '05 #10
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
Jul 22 '05 #11
"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.
Jul 22 '05 #12
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
Jul 22 '05 #13
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
Jul 22 '05 #14
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
Jul 22 '05 #15
"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?
Jul 22 '05 #16
"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?
Jul 22 '05 #17
"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?
Jul 22 '05 #18
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
Jul 22 '05 #19
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
Jul 22 '05 #20
"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?


Jul 22 '05 #21
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
Jul 22 '05 #22
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
Jul 22 '05 #23
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
Jul 22 '05 #24
"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.
Jul 22 '05 #25
"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.
Jul 22 '05 #26
"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?
Jul 22 '05 #27
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
Jul 22 '05 #28

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

Similar topics

20
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; ...
17
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...
32
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: ...
9
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;...
6
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;
6
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...
8
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...
13
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 {
3
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...
0
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,...
0
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...
1
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...
0
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...
0
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...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
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 ...
1
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
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...

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.