C ++以定义明确的方式将堆上的对象移动到本地对象中
C++ moving object on heap into local object in a well defined manner
是否可以将可移动堆实例移动到本地对象中?我有下面的示例代码:
#include <memory>
#include <type_traits>
#include <concepts>
#include <string>
template<std::move_constructible T>
struct LazyGuard
{
T value;
LazyGuard(T* const ptr) : value(std::move(*ptr)) { }
};
template <std::move_constructible T>
inline T&& MakeLocal(T* ptr)
{
return std::move(*ptr);
}
int main()
{
LazyGuard<std::string> guard(new std::string("Will be using with 'Socket* TCPSocket::FromAddress' kind of constructors"));
// Or another way
std::string local2 = MakeLocal(new std::string("similar thing"));
// Or another way
std::string local3(MakeLocal(new std::string("similar thing")));
return 0;
}
我想知道的是:
我们能保证会调用移动构造函数(或移动赋值运算符)吗?
代码是规范的,还是可以规范的?
我知道可以使用智能指针,但这不是我在这里要问的。
更新:为了解决泄漏问题,我在守卫构造函数中添加了 delete,因此改进了下面的示例。我找不到用“MakeLocal”示例执行此操作的方法,这有可能吗?:
template<std::move_constructible T>
struct LazyGuard
{
T value;
LazyGuard(T* const ptr) : value(std::move(*ptr)) { delete ptr; }
};
int main()
{
LazyGuard<std::string> guard(new std::string("Will be using with 'Socket* TCPSocket::FromAddress' kind of constructors"));
return 0;
}
Can we guarantee the move constructor (or move assignment operator) will be called?
是
就内存 allocation/deallocation 而言,堆与堆栈仅“意味着”任何事情。除此之外,它们实际上是无法区分的。一个对象是一个对象,无论它的内存位于何处。
对象从堆到堆、从栈到栈、从堆到栈、从栈到堆没有区别
简而言之:是的,您可以从堆上的实例安全地移动构造或移动分配基于堆栈的对象。
Is the code well-defined, or can it be made well-defined?
定义明确,但不规范。
注意我说的是move-construct。这不会破坏堆上的对象,只是将其 content 移动到堆栈。您仍然需要销毁原始对象。
就目前而言,您的代码正在泄漏大量内存。
编辑:LazyGuard
的更新构造函数将工作 而不会泄漏内存。但是,构造函数获取原始指针的所有权是非常非常糟糕的设计。
LazyGuard
真的应该这样写:
template<std::move_constructible T>
struct LazyGuard
{
T value;
LazyGuard(T v) : value(std::move(v)) {}
};
它的初始化器来自哪里是它业务的none,这是它用在哪里的问题。
是否可以将可移动堆实例移动到本地对象中?我有下面的示例代码:
#include <memory>
#include <type_traits>
#include <concepts>
#include <string>
template<std::move_constructible T>
struct LazyGuard
{
T value;
LazyGuard(T* const ptr) : value(std::move(*ptr)) { }
};
template <std::move_constructible T>
inline T&& MakeLocal(T* ptr)
{
return std::move(*ptr);
}
int main()
{
LazyGuard<std::string> guard(new std::string("Will be using with 'Socket* TCPSocket::FromAddress' kind of constructors"));
// Or another way
std::string local2 = MakeLocal(new std::string("similar thing"));
// Or another way
std::string local3(MakeLocal(new std::string("similar thing")));
return 0;
}
我想知道的是:
我们能保证会调用移动构造函数(或移动赋值运算符)吗?
代码是规范的,还是可以规范的?
我知道可以使用智能指针,但这不是我在这里要问的。
更新:为了解决泄漏问题,我在守卫构造函数中添加了 delete,因此改进了下面的示例。我找不到用“MakeLocal”示例执行此操作的方法,这有可能吗?:
template<std::move_constructible T>
struct LazyGuard
{
T value;
LazyGuard(T* const ptr) : value(std::move(*ptr)) { delete ptr; }
};
int main()
{
LazyGuard<std::string> guard(new std::string("Will be using with 'Socket* TCPSocket::FromAddress' kind of constructors"));
return 0;
}
Can we guarantee the move constructor (or move assignment operator) will be called?
是
就内存 allocation/deallocation 而言,堆与堆栈仅“意味着”任何事情。除此之外,它们实际上是无法区分的。一个对象是一个对象,无论它的内存位于何处。
对象从堆到堆、从栈到栈、从堆到栈、从栈到堆没有区别
简而言之:是的,您可以从堆上的实例安全地移动构造或移动分配基于堆栈的对象。
Is the code well-defined, or can it be made well-defined?
定义明确,但不规范。
注意我说的是move-construct。这不会破坏堆上的对象,只是将其 content 移动到堆栈。您仍然需要销毁原始对象。
就目前而言,您的代码正在泄漏大量内存。
编辑:LazyGuard
的更新构造函数将工作 而不会泄漏内存。但是,构造函数获取原始指针的所有权是非常非常糟糕的设计。
LazyGuard
真的应该这样写:
template<std::move_constructible T>
struct LazyGuard
{
T value;
LazyGuard(T v) : value(std::move(v)) {}
};
它的初始化器来自哪里是它业务的none,这是它用在哪里的问题。