Using a callback to consume data from std::vector<uint8_t> - c++

Based on the previous answers, I wrote a better buffer that can be consumed fast:
#include <iostream>
#include <vector>
#include <functional>
#include <stdio.h>
#include <string.h>
using namespace std;
template <class T>
class Buffer
{
public:
Buffer(size_t reserve) {
_buffer.reserve(reserve);
}
void write(T* buffer, size_t amountToWrite) {
this->_buffer.insert(this->_buffer.begin(), buffer, buffer + amountToWrite);
}
size_t consume(const size_t amountToConsume, std::function<void(T*, T*)> onConsume) {
if (_current==this->_buffer.size()) {
//this means we've already read everything. Maybe we should throw or just return 0?
return 0;
}
size_t currentActualSize = this->_buffer.size() - this->_current;
if (amountToConsume <= currentActualSize) {
onConsume(this->_buffer.data() + this->_current, this->_buffer.data() + this->_current + amountToConsume);
this->_current += amountToConsume;
return amountToConsume;
} else {
size_t remaining = currentActualSize;
onConsume(this->_buffer.data() + this->_current, this->_buffer.data() + this->_current + remaining);
this->_current += remaining;
return remaining;
}
}
private:
std::vector<T> _buffer;
size_t _current = 0;
};
int main()
{
Buffer<uint8_t> b(7);
uint8_t u[] = {1,2,3,4,5,6,7};
b.write(u, 7);
uint8_t r[3] = {255, 255, 255};
size_t consumedBytes2 = b.consume(3, [r](const uint8_t* begin, const uint8_t* end){
std::cout << "begin: " << begin << ", end: " << end << std::endl;
std::copy(begin, end, (uint8_t*)r);
});
std::cout << "consumed " << consumedBytes2 << std::endl;
for(int i=0; i<consumedBytes2; i++) {
std::cout << (int) r[i] << " - ";
}
std::cout << std::endl;
return 0;
}
and I added a callback that calls with the buffer begin and end, so I can write to whenever I want, instead of copying to a temporary buffer and then writing to another buffer.
However, as you can see, the output is:
begin: , end:
consumed 3
255 - 255 - 255 -
nothing is being written to my buffer.
What is happening?

You are capturing your array by value.
Capturing by reference will give you the expected result.
size_t consumedBytes2 = b.consume(3, [&r](const uint8_t* begin, const uint8_t* end){
std::cout << "begin: " << begin << ", end: " << end << std::endl;
std::copy(begin, end, (uint8_t*)r);
});
Capturing a pointer by value would have worked fine, but the array doesn't decay to a pointer here as it would when passed to a function.

Related

Can I create constexpr strings with functions?

I have a method that creates a file header with a given comment symbol, depending on the output file type. There are only a few supported file types, thus I want to create these headers at compile time. Can I make these as a constexpr ?
std::string create_header(const std::string &comment_symbol) {
std::string div(15, '-');
std::string space(2, ' ');
std::stringstream hdr;
hdr << comment_symbol << space << " Begin of File." << std::endl;
hdr << comment_symbol << space << div << std::endl;
return hdr.str();
}
std::string c_header() { return create_header("//"); }
std::string python_header() { return create_header("#");
Can I create constexpr strings with functions?
You can't return std::string, cause it allocates memory.
Can I make these as a constexpr ?
Sure, something along:
#include <array>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
template<size_t N> constexpr
auto create_header(const char (&comment_symbol)[N]) {
const char one[] = " Begin of File.\n";
const char two[] = " -\n";
std::array<char,
N + (sizeof(one) - 1) +
N + (sizeof(two) - 1) + 1
> ret{};
auto it = ret.begin();
for (const char *i = comment_symbol; *i; ++i) *it++ = *i;
for (const char *i = one; *i; ++i) *it++ = *i;
for (const char *i = comment_symbol; *i; ++i) *it++ = *i;
for (const char *i = two; *i; ++i) *it++ = *i;
return ret;
}
std::string c_header() {
constexpr auto a = create_header("//");
return std::string{a.begin(), a.end()};
}
int main() {
std::cout << c_header() << '\n';
}

C++ inline array member uniform initialization

Say that you have a class that has an array member:
class A
{
private:
uint8_t length;
uint8_t arr[10];
public:
A(uint8_t length, const uint8_t array[]): length(length)
{
memcpy(arr, array, length);
}
};
Then you have a global constant object and you want to use uniform initialization like this:
const A A_CONST{1,{23}};
In this case the compiler gives an error: "invalid conversion from 'int' to 'const uint8_t*"
But this works:
const uint8_t arr[]={23};
const A A_CONST{1,arr};
But then you have an unnecessary global constant "arr" also. I don't understand why the compiler can't cast {23} to const uint8_t* by looking at the constructor. Why is this so and is there a workaround?
The constructor you defined, is equivalent to
A(uint8_t length, const uint8_t *array)
This is, what the compiler is trying to tell.
To have an initialization as in your example, you must use either another type, or a std::initializer_list, e.g.
#include <algorithm>
#include <initializer_list>
A(const std::initializer_list<uint8_t> array)
: length(array.size())
{
std::copy(array.begin(), array.end(), arr);
}
Apart from that, don't use plain arrays or (length, pointer) arguments. Better use modern types like std::array or std::vector, this is less error prone and you get this kind of initialization for free.
If you really need to use an array (instead of std::vector) you can use this example:
#include <cstring>
#include <cstdint>
#include <iostream>
#include <initializer_list>
class A
{
private:
static const uint8_t MAX_LENGTH = 10;
uint8_t length;
uint8_t arr[MAX_LENGTH];
public:
A(uint8_t _length, const uint8_t array[]): length(_length)
{
if (length > MAX_LENGTH) { // to prevent copying out of memory
length = MAX_LENGTH;
}
std::memcpy(arr, array, length);
}
A(std::initializer_list<uint8_t> l): length(l.size())
{
if (length > MAX_LENGTH) { // to prevent copying out of memory
length = MAX_LENGTH;
}
std::initializer_list<uint8_t>::iterator it = l.begin();
for (uint32_t i = 0; (i < length) || (it == l.end()); ++i, ++it) {
arr[i] = *it;
}
}
uint8_t printAllForExample() const {
for (uint32_t i = 0; i < length; ++i) {
std::cout << (int)arr[i] << " ";
}
std::cout << std::endl;
}
uint8_t getLengthForExample() const {
return length;
}
};
int main() {
std::cout << "A_CONST_1:" << std::endl;
const A A_CONST_1{23};
A_CONST_1.printAllForExample();
std::cout << "A_CONST_2:" << std::endl;
const A A_CONST_2{};
std::cout << (int)A_CONST_2.getLengthForExample() << std::endl;
A_CONST_2.printAllForExample();
std::cout << "A_CONST_3:" << std::endl;
const A A_CONST_3{0,1,2,3,4,5,6,7,8,9};
std::cout << (int)A_CONST_3.getLengthForExample() << std::endl;
A_CONST_3.printAllForExample();
std::cout << "A_CONST_4:" << std::endl;
const A A_CONST_4{0,1,2,3,4,5,6,7,8,9,10,11,12};
std::cout << (int)A_CONST_4.getLengthForExample() << std::endl;
A_CONST_4.printAllForExample();
uint8_t data[] = {30,40,50};
std::cout << "A_CONST_5:" << std::endl;
const A A_CONST_5(3, data);
std::cout << (int)A_CONST_5.getLengthForExample() << std::endl;
A_CONST_5.printAllForExample();
return 0;
}

How can I improve the performance of this OpenCL Reduction Kernel code?

I've written code responsible for performing a Reduction on a large set of data, and while the code appears to be logically correct, it's proving to be slower than a simple std::accumulate or std::max_element call for the same data, and I'm looking for any insight into how I might have botched the performance of this code.
These are the results I'm getting. Note that even the raw time to execute the kernel is slower than a simple CPU reduction of my data.
Select which Device to use:
0: Cedar (AMD Accelerated P... - OpenCL 1.2 AMD-AP...)
1: Cedar (AMD Accelerated P... - OpenCL 1.2 AMD-AP...)
2: Intel(R) ... (AMD Accelerated P... - OpenCL 1.2 AMD-AP...)
3: Intel(R) ... (Experimental Open... - OpenCL 2.0 (Build...)
Device: Cedar
Platform: AMD Accelerated Parallel Processing
Num of compute units: 8
Work Group Size: 128
i = 9419918
Internal Duration: 95609555ns //Time to run just the kernel, no setup
Num of Work Groups to sum up: 78125
Reduced Value was detected to be: -5.06886
(Index): 1008460
Value at index is: -5.06886
Kernel Duration: 153748214ns //Includes copying of data, excludes building of kernel
Counting manually, Reduced Value is: -5.06886
(Index of): 1008460
Value at index is: -5.06886
Manual Duration: 48173322ns //CPU runtime using std::max_element`.
Press any key to continue . . .
The kernel code is constructed by concatenating all four of these files:
expand.cl
R"D(
#define EXPAND(type) \
typedef type Scalar;\
typedef type ## 2 Vector2;\
typedef type ## 4 Vector4;\
typedef type ## 8 Vector8;\
typedef type ## 16 Vector16;
)D"
float.cl
R"D(
EXPAND(float);
#define SCALAR_MAXIMUM INFINITY;
#define SCALAR_MINIMUM -INFINITY;
#define SCALAR_ZERO 0;
)D"
max.cl
R"D(
constant Scalar IDENTITY = SCALAR_MINIMUM;
#define REDUCE_IMPL(a, b, indexa, indexb, reduced_value, reduced_index) \
if(a > b) {\
reduced_value = a;\
reduced_index = indexa;\
} else {\
reduced_value = b;\
reduced_index = indexb;\
}
)D"
Reduction Main.cl
R"D(
kernel void reduce(global Scalar * a, global Scalar * output, local Scalar * scratch, global long * index_output, local long * index_scratch, long size) {
size_t gid = get_global_id(0);
size_t lid = get_local_id(0);
size_t wid = get_group_id(0);
size_t gsize = get_global_size(0);
size_t lsize = get_local_size(0);
size_t wsize = get_num_groups(0);
if(gid < size) {
scratch[lid] = a[gid];
index_scratch[lid] = gid;
} else {
scratch[lid] = IDENTITY;
index_scratch[lid] = -1;
}
barrier(CLK_LOCAL_MEM_FENCE);
for(size_t offset = lsize / 2; offset > 0; offset >>= 1) {
if(lid < offset) {
size_t indexa = index_scratch[lid];
size_t indexb = index_scratch[lid + offset];
Scalar a = scratch[lid];
Scalar b = scratch[lid + offset];
Scalar reduced_value;
size_t reduced_index;
REDUCE_IMPL(a, b, indexa, indexb, reduced_value, reduced_index);
scratch[lid] = reduced_value;
index_scratch[lid] = reduced_index;
}
barrier(CLK_LOCAL_MEM_FENCE);
}
if(lid == 0) {
output[wid] = scratch[0];
index_output[wid] = index_scratch[0];
}
}
)D"
CL Reduction.h perform_reduction:
std::future<result> perform_reduction(std::vector<T> const& values) {
cl_long size = values.size();
uint64_t num_of_work_groups = size / work_group_size;
int64_t global_size = work_group_size * num_of_work_groups;
if (global_size < size) {
num_of_work_groups++;
global_size = work_group_size * num_of_work_groups;
}
cl::Buffer input_buffer(context, CL_MEM_READ_ONLY, global_size * sizeof(T), nullptr);
std::vector<cl::Event> write_events(1);
queue.enqueueWriteBuffer(input_buffer, false, 0, size * sizeof(T), values.data(), nullptr, &write_events.back());
if (global_size != size) {
write_events.emplace_back();
queue.enqueueFillBuffer(input_buffer, reduction::identity<T>(), size * sizeof(T), (global_size - size) * sizeof(T), nullptr, &write_events.back());
}
return std::async([size, num_of_work_groups, global_size, input_buffer, write_events, this] {
cl::Buffer output_buffer( context, CL_MEM_WRITE_ONLY, num_of_work_groups * sizeof(T) );
cl::Buffer output_index_buffer(context, CL_MEM_WRITE_ONLY, num_of_work_groups * sizeof(cl_long));
kernel.setArg(0, input_buffer);
kernel.setArg(1, output_buffer);
kernel.setArg(2, sizeof(T) * work_group_size, nullptr);
kernel.setArg(3, output_index_buffer);
kernel.setArg(4, sizeof(cl_long) * work_group_size, nullptr);
kernel.setArg(5, size);
std::vector<cl::Event> kernel_event;
kernel_event.emplace_back();
queue.enqueueNDRangeKernel(kernel, {}, { uint64_t(global_size) }, { work_group_size }, &write_events, &kernel_event.back());
std::vector<T> results;
std::vector<int64_t> indexes;
results.resize(num_of_work_groups);
indexes.resize(num_of_work_groups);
queue.enqueueReadBuffer(output_buffer, false, 0, num_of_work_groups * sizeof(T), results.data(), &kernel_event);
queue.enqueueReadBuffer(output_index_buffer, false, 0, num_of_work_groups * sizeof(cl_long), indexes.data(), &kernel_event);
queue.finish();
std::cout << "Internal Duration: " << std::setw(11) << (kernel_event[0].getProfilingInfo<CL_PROFILING_COMMAND_END>() - kernel_event[0].getProfilingInfo<CL_PROFILING_COMMAND_START>()) << "ns" << std::endl;
std::cout << "Num of Work Groups to sum up: " << num_of_work_groups << std::endl;
result t{ reduction::identity<T>(), 0 };
for (size_t i = 0; i < results.size(); i++) {
T const& val = results[i];
size_t const& index = indexes[i];
t = reduction::reduce(t.reduced_value, val, t.reduced_index, index);
}
return t;
});
}
Reduction Main.cpp:
#define _HAS_AUTO_PTR_ETC 1
#include <vector>
#include <list>
#include <memory>
#include <utility>
#include<fstream>
#include<chrono>
#include<numeric>
#include<random>
#include<iomanip>
#include "CL Reduction.h"
std::string limit(std::string string, size_t limit) {
if (string.size() >= limit) return string.substr(0, limit - 3) + "...";
else return std::move(string);
}
cl::Device choose_device() {
std::vector<cl::Device> all_devices;
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
for (cl::Platform const& platform : platforms) {
std::vector<cl::Device> devices;
platform.getDevices(CL_DEVICE_TYPE_ALL, &devices);
all_devices.insert(all_devices.end(), devices.begin(), devices.end());
}
std::cout << "Select which Device to use: " << std::endl;
for (size_t i = 0; i < all_devices.size(); i++) {
cl::Device const& device = all_devices[i];
std::cout << i;
std::cout << ": ";
std::cout << std::setw(20) << limit(device.getInfo<CL_DEVICE_NAME>(), 20);
std::cout << " (";
std::cout << std::setw(20) << limit(cl::Platform{ device.getInfo<CL_DEVICE_PLATFORM>() }.getInfo<CL_PLATFORM_NAME>(), 20);
std::cout << " - ";
std::cout << std::setw(20) << limit(device.getInfo<CL_DEVICE_VERSION>(), 20);
std::cout << ")";
std::cout << std::endl;
}
size_t chosen;
std::cin >> chosen;
return all_devices[chosen];
}
int main() {
using type = float;
using reduction_type = cl_reduction_type::reduction_type<cl_reduction_type::type::maximum>;
using datatype = cl_datatype::datatype<type>;
using context_t = cl_reduction::reduction_context<datatype, reduction_type>;
std::ofstream err_log{ "err.txt" };
cl::Device device = choose_device();
try {
cl_reduction::reduction_context<datatype, reduction_type> context{ { device }, err_log };
std::vector<type> values;
auto last_ping = std::chrono::steady_clock::now();
std::default_random_engine engine{ std::random_device{}() };
std::uniform_real_distribution<type> distribution{ -100.f, 100.f };
//std::uniform_int_distribution<type> distribution(1, 500);
values.resize(10'000'000ull);
//values.resize(10'000);
type start = distribution(engine);
for (size_t i = 0; i < values.size(); i++) {
values[i] = start;
start = std::nextafter(start, std::numeric_limits<type>::infinity());
if (std::chrono::steady_clock::now() - last_ping > std::chrono::seconds(1)) {
std::cout << "i = " << i << '\r';
last_ping += std::chrono::seconds(1);
}
}
std::shuffle(values.begin(), values.end(), engine);
auto begin = std::chrono::steady_clock::now();
auto future = context.perform_reduction(values);
context_t::result t;
try {
t = future.get();
}
catch (cl::Error const& e) {
err_log << e.what() << std::endl;
err_log << e.err() << std::endl;
}
auto end = std::chrono::steady_clock::now();
std::cout << "Reduced Value was detected to be: " << t.reduced_value << std::endl;
std::cout << "(Index): " << t.reduced_index << std::endl;
std::cout << "Value at index is: " << values[t.reduced_index] << std::endl;
std::cout << "Kernel Duration: " << std::setw(11) << (end - begin).count() << "ns" << std::endl;
begin = std::chrono::steady_clock::now();
//auto value = std::accumulate(values.begin(), values.end(), type(0));
auto it = std::max_element(values.begin(), values.end());
auto index = std::distance(values.begin(), it);
auto value = values[index];
end = std::chrono::steady_clock::now();
std::cout << "Counting manually, Reduced Value is: " << value << std::endl;
std::cout << "(Index of): " << index << std::endl;
std::cout << "Value at index is: " << values[index] << std::endl;
std::cout << "Manual Duration: " << std::setw(11) << (end - begin).count() << "ns" << std::endl;
}
catch (cl::Error const& e) {
std::cerr << e.what() << ':' << e.err() << std::endl;
if (e.err() == CL_INVALID_BUFFER_SIZE)
std::cerr << device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() << std::endl;
}
system("pause");
return 0;
}
I've included the entire codebase here, which includes the three headers used and the main function. ("CL Datatype.h", "Cl Reduction Type.h", "CL Reduction.h", "Reduction Main.cpp"). I've only included for this post the code that I think is relevant, but if you think the problem is in something else, you can point to that in the Github Repo.
Read your input with Vector4 a = vload4(...) and use .xyzw. You might also try vectorizing by 8 with vload8.
Instead of a > b, use isgreater(a, b) along with any, all and select.
Do more than one reduction per loop to keep it in registers and reduce the bandwidth to the local memory. For a workgroup size of 128 and vector size of 4, the first thread would reduce 0-3 with 512-515, then with 1024-1027, etc. before writing to local memory with vstore4. Try different inner loop sizes.
As much as possible, you don't want threads sitting around doing nothing. The kernel should just be reducing from global memory into registers once, storing to local memory and then synchronizing the threads before one thread reduces from local to a single value for the kernel and store that in global memory. Finally, you can do the last, relatively small, level of reduction on the CPU. This level will only contain one value from each workgroup: total_size / (work_group_size = 128) / (vector_size = 4) / (inner_loop_size = 16)

Quick Sort applied to a vector of pointers to objects - infinite loop

I cannot figure out why the algorithm results in an infinite loop. I am trying to sort the vector according to the final price. The pivot always stays the same. Maybe the problem is with the swapping of the objects
Motorbike findPivotPricee(vector<Motorbike*>& available, int left, int right)
{
int center = (left + right) / 2;
if (available[center]->finalPrice() < available[left]->finalPrice())
{
swap(*available[left], *available[center]);
}
if (available[right]->finalPrice()< available[left]->finalPrice())
{
swap(*available[left], *available[right]);
}
if (available[right]->finalPrice() < available[center]->finalPrice())
{
swap(*available[center], *available[right]);
}
Motorbike pivot = *available[center];
swap(*available[center], *available[right - 1]);
return pivot;
}
void quickSortMotorbikeByPrice(vector<Motorbike*>& available, int left, int right)
{
int i = left;
int j = right-1;
Motorbike pivot = findPivotPricee(available, left, right);
cout << pivot.finalPrice() << endl;
while (i < j)
{
while (available[i]->finalPrice() < pivot.finalPrice())
{
i++;
}
while (available[j]->finalPrice() > pivot.finalPrice())
{
j--;
}
if (i <= j)
{
swap(*available[i], *available[j]);
i++;
j--;
}
else {
break;
}
}
swap(*available[i], *available[right - 1]);//restore the pivot
if (left < right) {
if (left<j) quickSortMotorbikeByPrice(available, left, j);
if (right>i) quickSortMotorbikeByPrice(available, i, right);
}
}
void quickSortMotorbikeByPrice(vector<Motorbike*>& available)
{
quickSortMotorbikeByPrice(available, 0, available.size() - 1);
}
Often, algorithms from wikipedia, e.g. the quicksort algorithms are hard to transform into a working implementation because they fail to point out the assumed programming model implied by the given algorithm. For example, if it is a 0 based or a 1 based array and that they assume that the indices used are signed not unsigned integers.
Then, people start trying to use those algorithms, here, for example in C++ and run into all sorts of problems. Quite a waste of time... And from looking at the code given in the question, I assume the author of the question tried to use info from wikipedia...
Since this is obviously homework, impress your teacher and use the code below. Quicksort is tricky to get right and it can take quite a while to find out if you should write lo = left + 1 or lo = left etc.
#include <cstdint>
#include <memory>
#include <vector>
#include <iostream>
#include <cassert>
template <class X>
void vswap(std::vector<X>& v, size_t i1, size_t i2)
{
X temp = v[i1];
v[i1] = v[i2];
v[i2] = temp;
}
template <typename X>
std::ostream& operator<<(std::ostream& stm, const std::vector<X>& v)
{
stm << "[|";
size_t i = 0;
for (auto& x : v)
{
if (0 == i)
stm << x;
else
stm << "; " << x;
i++;
}
stm << "|]";
return stm;
}
template <typename X>
std::ostream& operator<<(std::ostream& stm, const std::vector<X*>& v)
{
stm << "[|";
size_t i = 0;
for (auto& x : v)
{
if (0 == i)
if (nullptr == x) stm << "nullptr"; else stm << *x;
else
if (nullptr == x) stm << "; nullptr"; else stm << "; " << *x;
i++;
}
stm << "|]";
return stm;
}
template <class X, class Predicate>
size_t partition(std::vector<X> & v, Predicate p, size_t left, size_t right)
{
size_t boundary = left;
X x = v[boundary];
for (size_t i = left; i < right; i++)
{
if (p(v[i], x))
{
vswap(v, boundary, i);
boundary++;
}
}
return boundary;
}
template<class X, class Predicate>
void mysort(std::vector<X> & v, Predicate p, size_t left, size_t right)
{
//std::cout << "mysort: " << v << " " << left << " " << right << std::endl;
if ((right - left) > 1)
{
size_t boundary = partition(v, p, left, right);
//std::cout << "boundary = " << boundary << std::endl;
mysort(v, p, left, boundary);
mysort(v, p, boundary == left ? boundary + 1 : boundary, right);
}
}
class Motorbike
{
size_t m_id;
int32_t m_finalPrice;
public:
Motorbike()
: m_id(0)
, m_finalPrice(0)
{}
Motorbike(size_t id, int32_t finalPrice)
: m_id(id)
, m_finalPrice(finalPrice)
{}
void Id(size_t id)
{
m_id = id;
}
size_t Id() const
{
return m_id;
}
void Price(int32_t price)
{
m_finalPrice = price;
}
int32_t Price() const
{
return m_finalPrice;
}
};
std::ostream& operator<< (std::ostream& stm, const Motorbike& bike)
{
stm << "(" << bike.Id() << ", " << bike.Price() << ")";
return stm;
}
std::vector<Motorbike> randomBikes(size_t count, int32_t lowPrice = 100, int32_t highPrice = 1000)
{
std::vector<Motorbike> result;
result.resize(count);
for (size_t i = 0; i < count; i++)
{
result[i].Id(i);
result[i].Price(lowPrice + rand() * (highPrice - lowPrice) / RAND_MAX);
}
return result;
}
std::vector<Motorbike*> bikePointers(std::vector<Motorbike> & bikes)
{
std::vector<Motorbike*> result;
result.resize(bikes.size());
for (size_t i = 0; i < bikes.size(); i++)
{
result[i] = &bikes[i];
}
return result;
}
int main()
{
//_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF);
//_CrtDumpMemoryLeaks();
//{
//{
// std::vector<int32_t> data = { 3, 5, 1, 4, 2, 0 };
// std::cout << "original: " << data << std::endl;
// mysort(data, [](int32_t a, int32_t b) -> bool {return a < b;}, 0, data.size());
// std::cout << "sorted? " << data << std::endl;
//}
//std::cout << "--------------------------------------------------------" << std::endl;
//{
// std::vector<int32_t> data = { 3, 6, 1, 4, 2, 0, 5 };
// std::cout << "original: " << data << std::endl;
// mysort(data, [](int32_t a, int32_t b) -> bool {return a < b;}, 0, data.size());
// std::cout << "sorted? " << data << std::endl;
//}
for(size_t run = 0; run < 10; run++)
{
auto bikes = randomBikes(5+run%2);
auto bikes_p = bikePointers(bikes);
std::cout << "original: " << bikes_p << std::endl;
mysort(bikes_p, [](const Motorbike* m1, const Motorbike* m2)-> bool { return m1->Price() < m2->Price(); }, 0, bikes_p.size());
std::cout << "sorted? " << bikes_p << std::endl;
std::cout << "--------------------------------------------------------" << std::endl;
}
//}
//_CrtDumpMemoryLeaks();
return 0;
}

array of vector<struct> in C++

I've a vector of structure and it's components, now I want array of this group, below is my code
struct V1
{
USHORT val;
UINT cnt;
USHORT state;
};
struct V2
{
DWORD room;
vector <V1> vref;
bool update_V1(USHORT S1, USHORT S2);
VOID ClearState(USHORT S1);
};
struct V3
{
USHORT block;
vector <V2> V2ref;
bool Update_V2(DWORD S1,USHORT S2,USHORT S3);
VOID ClearState_V2(USHORT S4);
};
struct V4
{
USHORT space;
vector <V3> V3ref;
bool Update_V3(USHORT S1,DWORD S2,USHORT S3);
VOID ClearState_V2(USHORT S4);
};
struct V5
{
USHORT del_1;
vector <V4> V4ref;
bool Update_V4(USHORT S1,USHORT S2,DWORD S3,USHORT S4);
VOID ClearState_V2(USHORT S4);
};
class C1
{
vector<V5> V5ref[2];
bool UpdateGroup(USHORT S1,USHORT S2,USHORT S3,DWORD S4,USHORT S5);
}
bool C1::UpdateGroup(USHORT S1,USHORT S2,USHORT S3,DWORD S4,USHORT S5)
{
vector<V5>::iterator it;
for ( it=V5ref[S5].begin() ; it< V5ref[S5].end(); it++ )
{
if(it->del_1==S2)
{
return grpItr->Update_V4(S1,S2,S3,s4);
}
}
V5 V5local;
V5local.del_1 = S2;
V5local.Update_V4(S1,S2,S3,S4);
V5ref[S5].push_back(V5local);
return true;
}
I tried using vector V5ref[2];
It works for 1st iteration and throws error "assert" for 2nd iteration, what could be the reason. is there any other option to have copies of vectors.
what exactly I want to do is, with parameter S2 being 1, 2, 3, I want diff arrays of the whole vector for S2 = 1, S2 = 2...V5 and it's components should be seperate elements of the array according to S2
I have researched your problem a bit. Since the code is insufficient, we all can only guess what you are doing or not doing there. The debug assertion usually comes if the vector has not enough space allocated. (correct me if I am wrong). So, in this case, before using your vectors, you should use the resize(); method. Here is an example:
struct structure
{
int value1;
char value2;
bool value3;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<structure> vector1;
vector1.resize(1);
vector1[0].value1 = 12;
vector1[0].value2 = 'h';
vector1[0].value3 = true;
return 0;
}
If you test it yourself, you will know that without the vector.resize(1); this won't work at the run-time.
At any given time, a std::vector<> has a constraint, size which is the maximum element number you can access + 1, and a constraint capacity which is how many elements it can contain before it has to move the data to a larger memory allocation.
size determines what you can access. When the vector is created, you cannot access anything. vec[0] is illegal when the vector is empty.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> vec;
std::cout << "initially, vec.size = " << vec.size() << ", cap = " << vec.capacity() << "\n";
// initially, the vector is empty.
// std::cout << vec[0] << '\n'; // undefined behavior, probably a crash
// you can only ever access vec[n] where v < vec.size(),
// this vector is empty, so size() == 0
// Lets add a number to the vector.
vec.push_back(5);
std::cout << "now, vec.size = " << vec.size() << ", cap = " << vec.capacity()
std::cout << "vec[0] = " << vec[0] << '\n';
// std::cout << vec[1] << '\n'; // undefined behavior because 1 >= size()
vec.resize(5);
std::cout << "resized, vec.size = " << vec.size() << ", cap = " << vec.capacity()
vec[1] = 1; // valid, resize made space for vec[0] .. vec[4]
vec[2] = 2;
for (auto it = vec.begin(), end = vec.end(); it != end; ++it)
std::cout << *it << '\n';
return 0;
}
push_back does "vec.resize(vec.size() + 1)" for you, and then inserts the value being 'push_back'ed into the new slot.
resize attempts to make room for extra elements -- if size is 3 and you say resize(5) it will try to make room for 2 new elements.
If the result causes size to exceed capacity then the vector allocates a new array, copies the old data over into it, and releases the old array. This can become very expensive. If you know roughly how big your vector is going to become, you can avoid this relocation by calling reserve()
#include <iostream>
#include <vector>
using std::cout;
struct Stud // will always tell you when it reproduces
{
int m_i;
Stud() : m_i(-1) {}
Stud(int i) : m_i(i) {}
Stud(const Stud& rhs) : m_i(rhs.m_i) { cout << "Copying(Ctor) " << m_i << '\n'; }
Stud& operator=(const Stud& rhs) { m_i = rhs.m_i; cout << "Copying(=) " << m_i << '\n'; return *this; }
};
int main()
{
std::vector<Stud> studs;
studs.push_back(0);
studs.push_back(1);
studs.reserve(5);
studs.push_back(5); // remember, this adds to the back.
studs.push_back(6);
std::cout << "size of studs " << studs.size();
return 0;
}
Based on this
bool Update_V4(USHORT S1,USHORT S2,DWORD S3,USHORT S4);
I am guessing that you are trying to simulate multi-dimensional arrays of some kind, and you are doing something like
V4Ref[S1]
without checking
if (S1 < V4Ref.size())
C++ has a function 'assert' which will cause a Debug build application to terminate if a condition is not met.
#include <cassert>
#include <vector>
int main()
{
std::vector<int> vec;
assert(vec.size() == 0);
vec.push_back(1);
vec.resize(5);
vec.push_back(5);
assert(vec.size() == 10); // expect to crash here.
return 0;
}
You could use this to help catch bad sizes:
bool V4::Update_V4(USHORT S1,USHORT S2,DWORD S3,USHORT S4)
{
assert(S1 < V4ref.size());
return V4ref[S1].Update_V3(S2, S3, S4);
}