简体   繁体   English

防止类的临时实例化

[英]Prevent temporary instantiation of class

How can I prevent instantiation of temporary instances of a certain class?如何防止某个类的临时实例的实例化?

I've tried creating a method which can be called upon lvalue instances only and calling that method in the c'tor to prevent rvalue instantiations of the class in compile-time, but it didn't help -- the method was called successfully even for rvalue instantiations of the class.我已经尝试创建一个只能在左值实例上调用的方法,并在 c'tor 中调用该方法以防止在编译时类的右值实例化,但它没有帮助——该方法甚至被成功调用用于类的右值实例化。 It seems that the c'tor is oblivious to the fact that it's currently constructing an rvalue instance; c'tor 似乎没有注意到它当前正在构建一个右值实例; lvalue-only method calls are allowed either way.无论哪种方式都允许仅左值方法调用。

My goal is to create a scoped guard for allocations returned by WinApi , which must be freed via LocalFree .我的目标是为WinApi返回的分配创建一个范围保护,必须通过LocalFree释放。 I want to prevent from temporary instances of the class, which would cause immediate deallocation of the allocation, defeating the purpose of being a scoped guard.我想防止类的临时实例,这会导致分配的立即解除分配,从而破坏了成为范围保护的目的。 This might also cause unpredictable runtime behavior, because memory freed by LocalFree might still be accessible for some time after the function call.这也可能导致不可预测的运行时行为,因为在函数调用后的一段时间内, LocalFree释放的内存可能仍可访问。

If I interpret the question correctly, you should be fine with a RAII wrapper around your resource.如果我正确解释了这个问题,那么您应该可以在您的资源周围使用 RAII 包装器。

Here's an outline of how that could look:以下是其外观的概述:

#include <Windows.h>

#include <string>
#include <stdexcept>
#include <utility>

template<typename T>
class [[nodiscard]] ScopedAlloc {
public:
    ScopedAlloc(UINT uFlags, SIZE_T elems) : 
        hRes(LocalAlloc(uFlags, elems*sizeof(T)))
    {
        if (hRes == nullptr)
            throw std::runtime_error("ScopedAlloc failed " +
                                     std::to_string(GetLastError()));
    }

    // A constructor to take ownership of a HLOCAL created with LocalAlloc
    explicit ScopedAlloc(HLOCAL res) : hRes(res) {
        if(LocalSize(hRes) == 0)
            throw std::runtime_error("ScopedAlloc failed " +
                                     std::to_string(GetLastError()));
    }

    ScopedAlloc(const ScopedAlloc&) = delete; // or let it allocate and copy
    ScopedAlloc(ScopedAlloc&& rhs) : hRes(std::exchange(rhs.hRes, nullptr)) {}
    ScopedAlloc& operator=(const ScopedAlloc&) = delete; // or LocalReAlloc and copy
    ScopedAlloc& operator=(ScopedAlloc&& rhs) {
        std::swap(hRes, rhs.hRes);
        return *this;
    }

    ~ScopedAlloc() {
#ifndef NDEBUG
        if (hRes) { // fill memory with garbage in debug mode
            SIZE_T size = LocalSize(hRes);
            if (size) std::memset(hRes, 0xdd, size); // 0xDD - Dead Memory pattern
        }
#endif
        LocalFree(hRes);
    }

    operator const T* () const { return static_cast<T*>(hRes); }
    operator T* () { return static_cast<T*>(hRes); }

private:
    HLOCAL hRes;
};

Example usage:用法示例:

#include <iostream>

struct bar { int x, y; };

std::ostream& operator<<(std::ostream& os, const bar& b) {
    return os << '{' << b.x << ',' << b.y << '}';
}

int main() {
    ScopedAlloc<bar> foo(LMEM_FIXED | LMEM_ZEROINIT, 2);
    foo[0] = {1, 2};
    foo[1] = {3, 4};
    std::cout << foo[0] << ", " << foo[1] << '\n';    // prints   {1,2}, {3,4}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM