/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/WeakPtr.h" using mozilla::SupportsWeakPtr; using mozilla::WeakPtr; // To have a class C support weak pointers, inherit from SupportsWeakPtr<C>. class C : public SupportsWeakPtr<C> { public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C) int mNum; C() : mNum(0) {} ~C() { // Setting mNum in the destructor allows us to test against use-after-free below mNum = 0xDEAD; } void act() {} bool isConst() { return false; } bool isConst() const { return true; } }; bool isConst(C*) { return false; } bool isConst(const C*) { return true; } int main() { C* c1 = new C; MOZ_RELEASE_ASSERT(c1->mNum == 0); // Get weak pointers to c1. The first time, // a reference-counted WeakReference object is created that // can live beyond the lifetime of 'c1'. The WeakReference // object will be notified of 'c1's destruction. WeakPtr<C> w1 = c1; // Test a weak pointer for validity before using it. MOZ_RELEASE_ASSERT(w1); MOZ_RELEASE_ASSERT(w1 == c1); w1->mNum = 1; w1->act(); // Test taking another WeakPtr<C> to c1 WeakPtr<C> w2 = c1; MOZ_RELEASE_ASSERT(w2); MOZ_RELEASE_ASSERT(w2 == c1); MOZ_RELEASE_ASSERT(w2 == w1); MOZ_RELEASE_ASSERT(w2->mNum == 1); // Test a WeakPtr<const C> WeakPtr<const C> w3const = c1; MOZ_RELEASE_ASSERT(w3const); MOZ_RELEASE_ASSERT(w3const == c1); MOZ_RELEASE_ASSERT(w3const == w1); MOZ_RELEASE_ASSERT(w3const == w2); MOZ_RELEASE_ASSERT(w3const->mNum == 1); // Test const-correctness of operator-> and operator T* MOZ_RELEASE_ASSERT(!w1->isConst()); MOZ_RELEASE_ASSERT(w3const->isConst()); MOZ_RELEASE_ASSERT(!isConst(w1)); MOZ_RELEASE_ASSERT(isConst(w3const)); // Test that when a WeakPtr is destroyed, it does not destroy the object that it points to, // and it does not affect other WeakPtrs pointing to the same object (e.g. it does not // destroy the WeakReference object). { WeakPtr<C> w4local = c1; MOZ_RELEASE_ASSERT(w4local == c1); } // Now w4local has gone out of scope. If that had destroyed c1, then the following would fail // for sure (see C::~C()). MOZ_RELEASE_ASSERT(c1->mNum == 1); // Check that w4local going out of scope hasn't affected other WeakPtr's pointing to c1 MOZ_RELEASE_ASSERT(w1 == c1); MOZ_RELEASE_ASSERT(w2 == c1); // Now construct another C object and test changing what object a WeakPtr points to C* c2 = new C; c2->mNum = 2; MOZ_RELEASE_ASSERT(w2->mNum == 1); // w2 was pointing to c1 w2 = c2; MOZ_RELEASE_ASSERT(w2); MOZ_RELEASE_ASSERT(w2 == c2); MOZ_RELEASE_ASSERT(w2 != c1); MOZ_RELEASE_ASSERT(w2 != w1); MOZ_RELEASE_ASSERT(w2->mNum == 2); // Destroying the underlying object clears weak pointers to it. // It should not affect pointers that are not currently pointing to it. delete c1; MOZ_RELEASE_ASSERT(!w1, "Deleting an object should clear WeakPtr's to it."); MOZ_RELEASE_ASSERT(!w3const, "Deleting an object should clear WeakPtr's to it."); MOZ_RELEASE_ASSERT(w2, "Deleting an object should not clear WeakPtr that are not pointing to it."); delete c2; MOZ_RELEASE_ASSERT(!w2, "Deleting an object should clear WeakPtr's to it."); }