1. Introduction
1.1. Usual new and delete expressions
Note:For simplicity these examples ignore any class specific allocation or deallocation functions.
Given the new expression 
- 
     operator new ( sizeof ( T )) 
- 
     operator new ( sizeof ( T ), std :: align_val_t ( alignof ( T ))) 
Given the delete expression 
- 
     operator delete ( storage - ptr ) 
- 
     operator delete ( storage - ptr , std :: align_val_t ( alignof ( T ))) 
- 
     operator delete ( storage - ptr , sizeof ( T )) 
- 
     operator delete ( storage - ptr , sizeof ( T ), std :: align_val_t ( alignof ( T ))) 
When deallocation functions both with and without size parameters are present, it is unspecified which is selected.
Note:In both cases the preference for passing an alignment value depends on whether 
Going back to the case of 
- 
     operator new ( sizeof ( T )) 
- 
     operator delete ( storage - ptr , sizeof ( T )) 
 Here an additional size parameter is passed to the deallocation function.
1.2. Placement new expressions
Given the placement new expression 
- 
     operator new ( sizeof ( T ), args ...) 
- 
     operator new ( sizeof ( T ), std :: align_val_t ( alignof ( T )), args ...) 
If the initialisation of the 
Furthermore, unlike global deallocation functions, placement allocation functions are very intentionally provided context for the allocation. Since user allocation schemes are much less constrained than the global allocation and deallocation functions, it is conceivable that a user allocator providing a placement allocation function for ease use might be unable to deallocate the memory without being explicitly provided the size of the allocation. In fact this proposal was created after encountering just that scenario.
Note:The terms placement allocation function and placement deallocation function are not currently defined, but we take them to mean that set of allocation functions which are only ever selected by placement new expressions and not by usual new expressions, and the matching set of deallocation functions. See [CWG2592].
1.3. Usage with allocators
The following pattern, using a custom placement allocation function is somewhat common:
T * ptr = new ( alloc ) T ( args ...); 
If the construction throws an exception, and a matching placement deallocation function exists, it is invoked to free the allocated memory. That deallocation function does not have access to the size of the allocation. Therefore if 
2. Proposal
We propose to permit placement new expressions to use two partially matching deallocation functions:
- 
     operator delete ( storage - ptr , std :: size_val_t ( sizeof ( T )), args ...) 
- 
     operator delete ( storage - ptr , std :: size_val_t ( sizeof ( T )), std :: align_val_t ( alignof ( T )), args ...) 
For the backwards compatibility reasons explained in [P0035R4], which introduced 
namespace std { enum class size_val_t : size_t {}; } 
The new overloads, if available, should be used in preference to those existing ones without size parameters. This is because a deallocation function with access to the size is no less efficient than one without, and thanks to the new 
3. Alternatives
3.1. Library function
Any discussion of placement new and its deallocation behaviour raises the obvious question of placement deletion. Suppose one uses the placement new syntax to create objects of dynamic storage duration using some custom allocator: 
template < typename Allocator , typename T > void delete_via ( Allocator const & allocator , T * const ptr ) { std :: destroy_at ( ptr ); allocator . deallocate ( ptr , sizeof ( T )); } delete_via ( alloc , new ( alloc ) T ); 
Or possibly by a more general function template implementing placement delete via calls to placement deallocation functions:
delete_via ( alloc )( new ( alloc ) T ); 
Why then, should we not also use a function template for the object creation instead of placement new?
template < typename T , typename Allocator , typename ... Args > requires std :: constructible_from < T , Args ... > T * new_via ( Allocator const & allocator , Args && ... args ); // new (alloc) T(a, b, c); new_via < T > ( alloc , a , b , c ); 
That is indeed possible and allows one to solve the problem in library, but there are some major drawbacks:
- 
     Syntax 
 The placement new syntax provides direct syntactic access to the object initialisation, which has real benefits:- 
       An emplace T 
- 
       Directly initialising the object allows for more expressive forms of initialisation, such as designated initialisation: new ( alloc ) T { . a = x , . b = y } 
- 
       The initialisation of T new_via 
 These things can still of course be achieved in library using a lambda, but this further degrades the user experience: new_from_result_of ( alloc , [ & ]() { return T { . a = x , . b = y }; }) 
- 
       
- 
     Existing usage 
 The placement new syntax already exists and is widely used. Instead of inventing a new library alternative, we can improve the performance of code already out there and enable the same code to work correctly with new kinds of user-defined allocators.