-2

I was trying to clear all data in a vector without changing its size using memset. But after memset operation size of vector becomes 0. Here is the exact code:

std::vector<T> buckets[2];
MAX_BUCKET_SIZE=16;

Constructor:

buckets[0].resize(MAX_BUCKET_SIZE);
std::cout << "Actual size0 " << buckets[0].size() << std::endl;
buckets[1].resize(MAX_BUCKET_SIZE);
std::cout << "Actual size1 " << buckets[1].size() << std::endl;

in a function:

std::cout << "Actual size2 0 " << buckets[0].size() << std::endl;
std::cout << "Actual size2 1 " << buckets[1].size() << std::endl;
...
...
while (...){
    delete_data(current_bucket);

    std::cout << "current bucket ** " << current_bucket << std::endl;
    std::cout << "Actual size3 0 " << buckets[0].size() << std::endl;
    std::cout << "Actual size3 1 " << buckets[1].size() << std::endl;
}

delete_data function:

memset(&buckets[bucket_id], 0, sizeof(buckets[bucket_id]));

output:

Actual size0 16
Actual size1 16
Actual size2 0 16
Actual size2 1 16
current bucket ** 1
Actual size3 0 16
Actual size3 1 0
current bucket ** 0
Actual size3 0 0
Actual size3 1 0
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
SS306
  • 157
  • 1
  • 3
  • 9
  • 4
    So you have *array of vectors*? Why in the world...? – CinCout Feb 16 '16 at 10:46
  • Don't do `memset` on vectors, it is undefined behavior. – n. m. could be an AI Feb 16 '16 at 10:49
  • 4
    You `memset`, i.e. completely clobber, an *object*, and wonder why there's strange behaviour? – DevSolar Feb 16 '16 at 10:49
  • 1
    Using `memset` on an object that's not trivially copyable ([docs](http://en.cppreference.com/w/cpp/string/byte/memset)) is undefined. – molbdnilo Feb 16 '16 at 10:50
  • About array of vectors: Does it effect memset in any way? I dont see any.. Also any harm in doing that ? – SS306 Feb 16 '16 at 10:51
  • 3
    This is like cleaning your car with a flamethrower and wondering why it exploded to your face... joke aside, mixing C idioms with C++ classes is bad ! – SirDarius Feb 16 '16 at 10:52
  • You can just use a *vector of vectors* - `std::vector< std::vector< T > >`. Why mix C++ with C! – CinCout Feb 16 '16 at 10:53
  • 1
    @SasidharSanapala: Aside from writing to an object's internal state directly being formally undefined behaviour, a `std::vector` usually contains 1) a *pointer* to where it keeps its elements, and 2) an integer value holding the *size* of the vector. So not only did your `memset` **not** overwrite the actual data (which is kept elsewhere), you just zeroed the size and leaked the allocated memory. And since the object is not *aware* that you just gutted its internal state, your program might crash & burn at any time. *Do not mix C and C++ coding styles.* No good comes from it. – DevSolar Feb 16 '16 at 10:54

4 Answers4

7

I was trying to clear all data in a vector without changing its size using memset.

It's not going to work, because it does not pay attention to the area being filled. The way you apply it also creates a memory leak in situations when std::vector is implemented using pointers, because pointers are being zeroed out.

Use std::fill instead:

std::fill(buckets[0].begin(), buckets[0].end(), 0);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Does std::fill fill vector byte by byte or does it try to make each element in vector 0? What happens in case of vector >? – SS306 Feb 16 '16 at 11:16
  • 1
    @Sasidhar No, it does not work on such a low level. You have to pass something convertible to `std::pair`. – LogicStuff Feb 16 '16 at 11:18
  • @SasidharSanapala std::fill requires you to pass something convertible to vector's element. In case of int pair this could be make_pair(0,0). – Sergey Kalinichenko Feb 16 '16 at 11:21
  • @SasidharSanapala As far as the actual filling goes, std::fill relies on the iterator to set the value. – Sergey Kalinichenko Feb 16 '16 at 11:22
  • @dasblinkenlight So is there any anything equivalent to memset of an array in c++? Like setting all bytes to 0. Since i am writing a template class, looks like i cannot use something like std::fill. I don't want to fill it with junk. – SS306 Feb 16 '16 at 11:26
  • @Sasidhar You're completely wrong. Look up what T in STL stands for. Anyways, I showed you the awfully appalling `memset` version in my answer. – LogicStuff Feb 16 '16 at 11:30
  • @SasidharSanapala you can fill it with the default value of T, for example, by declaring T empty; and then calling std::fill(v.begin(), v.end(), empty); – Sergey Kalinichenko Feb 16 '16 at 11:42
3

Not to mention memset on non-POD is undefined behavior, it looks like you've just "succeeded" memset-ing the vector's internal data - that could be pointer to implementation or pointers to start/end of the underlying array. You didn't modify the elements and you effectively lost them (and leaked a memory).

You most probably wanted to operate on the underlying array (still, T has to be POD):

memset(&buckets[bucket_id].front(), 0, buckets[bucked_id].size() * sizeof(T));

But nobody does this in C++, because there are STL solutions, like std::fill:

std::fill(buckets[bucket_id].begin, buckets[bucket_id].end(), T{});

which will fill the array with copies of default-constructed T (which can be non-POD).

Also note that sizeof(buckets[bucket_id]) gives you completely pointless number for this occasion.

Community
  • 1
  • 1
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
1

Don't do that. Trashing the automatic storage of an instance of a class will probably lead to undefined behaviour. For example, I imagine that any destructors of the vector's elements will not be called.

Calling resize to zero will achieve essentially the same thing. Or just reassign buckets to a new instance of std::vector<T>.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

You're doing memset on a class, which is undefined behavior at best. How do you know what setting the memory used by the object to zero makes sense for the object? For example, if the vector stores a pointer to the items it contains then you've set that pointer to null, and thus caused a memory leak.

If you're lucky, you'll crash, if you're unlucky you won't.

Sean
  • 60,939
  • 11
  • 97
  • 136
  • If the class is a non-polymorphic type with only one member, then the behaviour is defined. – Bathsheba Feb 16 '16 at 10:52
  • @Bathsheba - really? So if my class just contains a `std::shared_pointer` then it's safe for me to `memset` its memory to zero? – Sean Feb 16 '16 at 11:03
  • That's more to do with UB on the `memset` of that specific member. Agree though that my comment is clear. – Bathsheba Feb 16 '16 at 11:04