1

I want to write a function which can modify element for all container which space is continueous, like, vector, int*. char* ....

here is my code:

#include <vector>
#include <string>
#include <iostream>

using namespace std;

template <typename T>
void test(T* t, size_t size) {
  for (size_t i = 0; i < size; ++i) {
    // *(t + i * sizeof(size_t)) += 2;
    *(t + i * sizeof(size_t)) = *(t + i * sizeof(size_t)) + 2;
    // cout << *reinterpret_cast<int*>(t + sizeof(size_t) * i) << endl;
  }                                                                                                                                                                                                        
}

int main() {
  std::vector<size_t> a = {1,2,3,4};
  test(&a[0], 4);  // print result is: 3, 2,3,4, which only modify the first element
  int b[4] = {1,2,3,4};
  test(b, 4); // print result is: 3, 2,3,4, which only modify the first element
  for (size_t i = 0; i < a.size(); ++i) {
    cout << a[i] << " ";
  }
  for (size_t i = 0; i < 4; ++i) {
    cout << b[i] << " ";
  }
}

please see the notes in code, i think when i use *(t + i * sizeof(size_t)), it will find the next int position, but it failed, can anyone help on this?

user3386109
  • 34,287
  • 7
  • 49
  • 68
xyhuang
  • 414
  • 3
  • 11
  • "I want to write a function which can modify element for all container which space is continueous, like, vector, int*. char*" Then do what the standard library does, and accept a pair of iterators (pointers are a kind of iterator). – Karl Knechtel Sep 22 '20 at 02:05

2 Answers2

2

If you want to add 2 to each element of a collection, C++ already provides a way to do that:

std::vector<size_t> a = {1,2,3,4};
std::transform(a.begin(), a.end(), a.begin(), [](int i){ return i + 2; });

This has a few obvious advantages over your code:

  1. it works with non-contiguous collections (as well as contiguous ones)
  2. it separates the iteration from the operation carried out one each item
  3. it's already debugged and heavily tested
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • @xyhuang I think `std::for_each` is the better candidate if you weren't planning to put them in another container. – Ranoiaetep Sep 22 '20 at 05:14
1

There's no need to multiply the offset by sizeof(size_t) in this expression:

*(t + i * sizeof(size_t))

Since the type of the pointer is known to be T, adding i to the pointer will point it at the next object. So you can just do:

*(t + i)

Of course, the usual way to write that is:

t[i]

Also, this call is incorrect:

std::vector<size_t> a = {1,2,3,4};
test(&a[0], 4);

If you want to treat the vector as an array like you're doing, you need to use the data method like this:

test(a.data(), 4);

Here's a demo.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • thanks a lot, i think it's a simple question, just forget the simple way. thank you very much – xyhuang Sep 22 '20 at 01:58
  • @xyhuang See the update. Your call using vector is wrong. – cigien Sep 22 '20 at 02:01
  • one more question, when i call *(t + i * sizeof(size_t)) ,i think it will visit unknown memory address, why it is not crashed(like segment fault) – xyhuang Sep 22 '20 at 02:01
  • @xyhuang Refer to [this](https://stackoverflow.com/questions/671703/array-index-out-of-bound-in-c) to find out reason of not crash. – rustyhu Sep 22 '20 at 03:13