代码之家  ›  专栏  ›  技术社区  ›  golosovsky

防止类的临时实例化

  •  0
  • golosovsky  · 技术社区  · 6 年前

    如何防止实例化某个类的临时实例?

    我尝试创建一个只能在左值实例上调用的方法,并在c'tor中调用该方法,以防止在编译时对类进行右值实例化,但无济于事——即使对类的右值实例化也成功调用了该方法。c'tor似乎忘记了它当前正在构造一个右值实例的事实;无论哪种方式都只允许使用左值方法调用。

    我的目标是为返回的分配创建一个范围保护 WinApi ,必须通过以下方式释放 LocalFree . 我想防止类的临时实例,这会导致分配的立即释放,从而违背了作为一个类的目的 范围 警卫。 这也可能导致不可预测的运行时行为,因为 本地免费 在函数调用后的一段时间内可能仍然可以访问。

    0 回复  |  直到 6 年前
        1
  •  1
  •   Ted Lyngmo    6 年前

    如果我正确地解释了这个问题,你应该可以用RAII包装你的资源。

    以下是对其外观的概述:

    #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;
    };
    

    示例用法:

    #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}
    }