In my custom ArrayProxy class. I have this test.
"array_proxy_initializer_list"_test = [] {
ArrayProxy<int> array = { 1, 2, 3, 4, 5 };
expect(array.size() == 5);
expect(array[0] == 1);
expect(array[1] == 2);
expect(array[2] == 3);
expect(array[3] == 4);
expect(array[4] == 5);
LogInfo{array[0]};// in release log: 1166876000
LogInfo{array[1]};// in release log: 32758
};
In debug mode. It work fine. And in release mode. It fails.
Here are my ArrayProxy class.
template<typename T>
concept ContainerObject = requires(T t) {
t.data();
t.size();
};
template<typename T>
class ArrayProxy
{
public:
using value_type = T;
constexpr ArrayProxy() : m_count(0), m_ptr(nullptr) {}
constexpr ArrayProxy(std::nullptr_t) : m_count(0), m_ptr(nullptr) {}
ArrayProxy(const T& value) : m_count(1), m_ptr(&value) {}
ArrayProxy(std::size_t count, const T* ptr) : m_count(count), m_ptr(ptr) {}
ArrayProxy(const std::initializer_list<T>& args) : m_count(args.size()), m_ptr(args.begin()) {}
ArrayProxy(ContainerObject auto container) : m_count(container.size()), m_ptr(container.data()) {}
template<std::size_t N>
ArrayProxy(const T (&ptr)[N]) : m_count(N), m_ptr(ptr) {};
const T& operator[](int i) const
{
return m_ptr[i];
}
std::size_t size() const
{
return m_count;
}
const T* data() const
{
return m_ptr;
}
private:
const T* m_ptr;
std::size_t m_count;
};
In my debug. I find a interesting behavior.
If I swap the order of m_ptr and m_count.
private:
std::size_t m_count;
const T* m_ptr;
};
In both debug and release mode. It works fine.
I don't know why, Is there a ub in my code?
compile on msvc 2022 and c++20.
Thanks for @Peter. I know how to test this class. The std::initializer_list's life time if from function's call to return.
This class is used to wrap some c api likevoid c_api(int* data, int size);
.
Use this class is friendly with modern cpp containers.
For example.
void c_api_wrapped(const ArrayProxy<int>& arr)
{
c_api(arr.data(), arr.size());
}
void test()
{
c_api_wrapped(1);
c_api_wrapped({1,2,3});
std::vector<int> arr = {1,2,3};
c_api_wrapped(arr);
}
It is friendly for these temporary value called.
But my use-case is in a wrong way. This class can only use in function's param.
If I use this as a variable in other way. The std::initializer_list would be destroyed.
So I should change my test to:
void test_array_proxy(const rain::ArrayProxy<int>& arr, const std::vector<int>& ground_truth)
{
boost::ut::expect(arr.size() == ground_truth.size());
for(int i = 0; i < arr.size(); ++i)
{
boost::ut::expect(arr[i] == ground_truth[i]);
}
}
int main()
{
"array_proxy_initializer_list"_test = [] {
std::vector<int> ground_truth = { 1, 2, 3, 4, 5 };
test_array_proxy({ 1, 2, 3, 4, 5 }, ground_truth);
};
}
It will work fine and it show this class's usage.
As I mentioned this class is from vulkan-hpp. The vulkan-hpp also provided a `ArrayProxyNoTemporaries" to prevent these situation.
Thanks for your help!