Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » U++ Core » Doubt with Buffer<> of a trivially destructible type
Doubt with Buffer<> of a trivially destructible type [message #61220] Thu, 12 December 2024 12:58 Go to next message
koldo is currently offline  koldo
Messages: 3437
Registered: August 2008
Senior Veteran
Hello all

Compiling this code with CLANG, I get the error: "object expression of non-scalar type 'double[3]' cannot be used in a pseudo-destructor expression" in the line with Buffer.
However, vector3_destructible gets true.
I wanted to ask you how to use Buffer for such a data type, or if there is a better dynamic container.

typedef double Vector3[3];

bool vector3_destructible = std::is_trivially_destructible<Vector3>::value;

Buffer<Vector3> vector3_data(10);


Best regards
Iñaki
Re: Doubt with Buffer<> of a trivially destructible type [message #61221 is a reply to message #61220] Thu, 12 December 2024 14:15 Go to previous messageGo to next message
Oblivion is currently offline  Oblivion
Messages: 1209
Registered: August 2007
Senior Contributor
Hello Iñaki,

Quote:

However, vector3_destructible gets true.


Yes, because std::is_trivially_destructible removes all extents (dimensions) of the object in question before its type gets evaluated. So, basically it is returning true for double type.

However, Buffer<Vector3> doesn't. So it expands into Buffer<double[3]>, hence the error.

I think you should instead prefer -if possible- a structure or Buffer<double> mybuffer(count * 3).

Then again, I don't know the exact requirements of your code.


Best regards,
Oblivion


[Updated on: Thu, 12 December 2024 14:17]

Report message to a moderator

Re: Doubt with Buffer<> of a trivially destructible type [message #61223 is a reply to message #61220] Thu, 12 December 2024 14:40 Go to previous messageGo to next message
Oblivion is currently offline  Oblivion
Messages: 1209
Registered: August 2007
Senior Contributor
However, this should work too:

CONSOLE_APP_MAIN
{
	typedef std::array<double, 3> Vector3;

	Buffer<Vector3> vector3_data(10, {1.0, 2.0, 3.0});

	for(int i = 0; i < 10; i++) {
		auto a = vector3_data[i];
		Cout() << a[0] << " "<<  a[1] << " " << a[2] << "\r\n";
	}
	
}



Or, C++17 style:

	typedef std::array<double, 3> Vector3;

	Vector<Vector3> vector3_data(10, {1.0, 2.0, 3.0});

	for(auto& [a, b, c] : vector3_data) {
		Cout() << a << " "<<  b << " " << c << "\r\n";
	}
	



Best regards,
Oblivion


[Updated on: Thu, 12 December 2024 14:43]

Report message to a moderator

Re: Doubt with Buffer<> of a trivially destructible type [message #61224 is a reply to message #61223] Thu, 12 December 2024 16:05 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3437
Registered: August 2008
Senior Veteran
Thank you Oblivion

Yes, there are simple solutions. This case is to alloc data to be filled by a DLL made in Delphi, with particular alignment requirements.

I have reviewed deeper in how U++ handles this, and it takes care of that in run time:
void Free() {
	if(ptr) {
		if(std::is_trivially_destructible<T>::value)  // <<========
			MemoryFree(ptr);
		else {
			void *p = (byte *)ptr - 16;
			size_t size = *(size_t *)p;
			Destroy(ptr, ptr + size);             // <<======== Destroy() is called only if there is a destructor
			MemoryFree(p);
		}
	}
}

However the compiler detects this:
template <class T>
inline void Destruct(T *t)
{
	t->~T();                        // error: object expression of non-scalar type 'double[3]' cannot be used in a pseudo-destructor expression
}

template <class T>
inline void Destroy(T *t, const T *end)
{
	while(t != end)
		Destruct(t++);
}


Best regards
Iñaki
Re: Doubt with Buffer<> of a trivially destructible type [message #61243 is a reply to message #61224] Sat, 14 December 2024 19:19 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 656
Registered: March 2007
Contributor
This is a valid use case, and something need to be addressed in u++ libary directly instead of circling around.

Here is a simple utility we can use to fix it from with u++ libary

template <typename T, std::size_t...>
constexpr auto object_count(T& t)
{
	return 1u;
}

template <std::size_t ... Ns, typename T, std::size_t n>
constexpr auto object_count(T (&arr)[n] )
{
	return n * object_count(arr[0]);
}

   // eg, with
    double d;
    double a1[5];
    double a2[5][3];
    double a3[5][4][2];

    // then
    static_assert(object_count(d)==1,"?");
    static_assert(object_count(a1)==5,"?");
    static_assert(object_count(a2)==15,"?");
    static_assert(object_count(d3)==40,"?);


With above utility, we can easily modify u++ Vector to accomodate c style array.

basially, if T is trivially relocatible, then
any c array of T is alos trivially relocatible,
Upp::Vector don't care any detail of c array, except the total number of T objects in the array to properly construct, move and destruct it, with T::~T() properly defined of course.

Oh, for
     // some type T
     T d3[3][2][5];


a simple
      sizeof(d3)/sizeof(T)

will do the job Smile
Re: Doubt with Buffer<> of a trivially destructible type [message #61244 is a reply to message #61243] Sat, 14 December 2024 20:45 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3437
Registered: August 2008
Senior Veteran
Hi Lance

Thank you for your response.
I have to say that std::vector has the same problem, but it is also true that we like to do things better than the standard library. Cool

One difficulty we have with CLANG is that although in U++ we try to handle the problem at run time, CLANG detects the problem at compile time.
Therefore, the solution has to work at compile time.


Best regards
Iñaki
Re: Doubt with Buffer<> of a trivially destructible type [message #61246 is a reply to message #61244] Sat, 14 December 2024 20:53 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 656
Registered: March 2007
Contributor
I believe this is something that should and can be addressed of at compile time by making Upp::Vector more robust.

I am surprised std::vector is guilty of the same problem. I will take a look to see if more recent standard library has fixed it.
Re: Doubt with Buffer<> of a trivially destructible type [message #61247 is a reply to message #61246] Sat, 14 December 2024 21:02 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 656
Registered: March 2007
Contributor
Hello Koldo,

It should not matter whether T is trivially destructible. As long as T is Upp::Moeavable, a type of fixed sized c array of T should be Vector friendly.

For example ,
typedef Upp::String S[3];

Upp::Vector<S3> s3s;


should compile and behave fine with a c array-awared Vector.
Re: Doubt with Buffer<> of a trivially destructible type [message #61249 is a reply to message #61247] Sat, 14 December 2024 21:37 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 656
Registered: March 2007
Contributor
My bad. I was wrong. a c array cannot be returned from a function; this disqualifies a c-array be used directly in a vector type (std::vector or Upp::Vector).

And I just noticed that I am completely off topic Sad

[Updated on: Sat, 14 December 2024 21:39]

Report message to a moderator

Re: Doubt with Buffer<> of a trivially destructible type [message #61250 is a reply to message #61246] Sun, 15 December 2024 12:25 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3437
Registered: August 2008
Senior Veteran
Lance wrote on Sat, 14 December 2024 20:53
I believe this is something that should and can be addressed of at compile time by making Upp::Vector more robust.

I am surprised std::vector is guilty of the same problem. I will take a look to see if more recent standard library has fixed it.

Yes. This code gives the same error:
CONSOLE_APP_MAIN
{
	typedef double Vector3[3];
		
	std::vector<Vector3> vector3_data(10);
}

Because of this in file clang\include\c++\v1\__memory\allocator.h:
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void destroy(pointer __p) { __p->~_Tp(); }


Best regards
Iñaki
Re: Doubt with Buffer<> of a trivially destructible type [message #61251 is a reply to message #61250] Sun, 15 December 2024 12:45 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3437
Registered: August 2008
Senior Veteran
The solution for U++ could be any of these, applied to class Buffer<> functions Malloc() and Free():

- For C++ 17, just insert constexpr in the std::is_trivially_destructible check, to force it to work in compile time:
if constexpr (std::is_trivially_destructible<T>::value)


- In C++ it is a little more complicated as it requires a little of SFINAE. This way the std::is_trivially_destructible check works in compile time:

	template <typename U = T>
	typename std::enable_if<!std::is_trivially_destructible<U>::value>::type
	Malloc(size_t size) {
		void* p = MemoryAlloc(size * sizeof(U) + 16);
		*(size_t*)p = size;
		ptr = (U*)((byte*)p + 16);
	}
	template <typename U = T>
	typename std::enable_if<std::is_trivially_destructible<U>::value>::type
	Malloc(size_t size) {
		ptr = (U*)MemoryAlloc(size * sizeof(U));
	}

	template <typename U = T>
	typename std::enable_if<!std::is_trivially_destructible<U>::value>::type
	Free() {
		if (ptr) {
			void* p = (byte*)ptr - 16;
			size_t size = *(size_t*)p;
			Destroy(ptr, ptr + size);
			MemoryFree(p);
		}
	}
	template <typename U = T>
	typename std::enable_if<std::is_trivially_destructible<U>::value>::type
	Free() {
		if (ptr) {
			MemoryFree(ptr);
		}
	}


Best regards
Iñaki
Re: Doubt with Buffer<> of a trivially destructible type [message #61252 is a reply to message #61251] Sun, 15 December 2024 14:29 Go to previous messageGo to next message
Lance is currently offline  Lance
Messages: 656
Registered: March 2007
Contributor
The inablility for Vector to desctruct T[n] is a consequence of inherited inability for a function to return a c array.

For example
     T Vector::pop();


requires the housed type T be returnable.

There is no reason for c++ to systematically disallow it other than c says so, and there is liitle or no incentive for c++ to do otherwise, as it can be easily circled around.

We can have our Vector to work with T[n] if it's really really desirable, by encapuslating it in an intermediate struct Vector::ArrayWrapper automatically.
ArrayWrapper is contructible from, assignable from, convertible to the array type.

There is some work involved. And the requirement is less common to make it worthy.
Re: Doubt with Buffer<> of a trivially destructible type [message #61331 is a reply to message #61251] Thu, 26 December 2024 18:47 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14260
Registered: November 2005
Ultimate Member
- For C++ 17, just insert constexpr in the std::is_trivially_destructible check, to force it to work in compile time:
if constexpr (std::is_trivially_destructible<T>::value)


We are now C++17 -> used this one
Re: Doubt with Buffer<> of a trivially destructible type [message #61338 is a reply to message #61331] Fri, 27 December 2024 18:34 Go to previous message
koldo is currently offline  koldo
Messages: 3437
Registered: August 2008
Senior Veteran
mirek wrote on Thu, 26 December 2024 18:47
- For C++ 17, just insert constexpr in the std::is_trivially_destructible check, to force it to work in compile time:
if constexpr (std::is_trivially_destructible<T>::value)


We are now C++17 -> used this one
Thank you Mirek. Problem solved!


Best regards
Iñaki
Previous Topic: How to respond when memory is exceeded
Next Topic: Stream Load serialization fired twice
Goto Forum:
  


Current Time: Tue Jun 03 03:17:30 CEST 2025

Total time taken to generate the page: 0.03501 seconds